diff --git a/README.md b/README.md
index 1a0b063..990de7f 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,11 @@ Using PayPal Payments Standard IPN:
...
INSTALLED_APPS = (... 'paypal.standard.ipn', ...)
...
+ PAYPAL_TEST = False # sandbox or not mode and True for live mode
PAYPAL_RECEIVER_EMAIL = "yourpaypalemail@example.com"
+ PAYPAL_IMAGE = 'https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif'
+ # default button image is http://images.paypal.com/images/x-click-but01.gif, for a list see:
+ # https://cms.paypal.com/cms_content/US/en_US/files/developer/paypal_button_chart_en.html
1. Create an instance of the `PayPalPaymentsForm` in the view where you would
like to collect money. Call `render` on the instance in your template to
@@ -45,6 +49,8 @@ Using PayPal Payments Standard IPN:
# What you want the button to do.
paypal_dict = {
"business": "yourpaypalemail@example.com",
+ #"image": "https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif"
+ "image_url": "http://www.example.com/your-header-logo-image.jpg", # max height: 98px width: 794px
"amount": "10000000.00",
"item_name": "name of the item",
"invoice": "unique-invoice-id",
@@ -65,6 +71,25 @@ Using PayPal Payments Standard IPN:
Show me the money!
{{ form.render }}
+
+ a. Alternatively you can create an intermediate view that performs pre-payment required processing and
+ then redirects to the PayPal processing page.
+
+ class PaymentPreProcessView(RedirectView):
+ """ Verifies cart is ready for payment - things like shipping cost is calculated """
+ permanent = False
+
+ def get_redirect_url(self, **kwargs):
+ """ Return the URL redirect to. URL matches are passed as kwargs"""
+ ...
+ pre-payment code here
+ ...
+ paypal_dict = {
+ "business": "yourpaypalemail@example.com",
+ ... }
+
+ form = PayPalPaymentsForm(initial=paypal_dict)
+ return form.render_as_GET_url()
1. When someone uses this button to buy something PayPal makes a HTTP POST to
your "notify_url". PayPal calls this Instant Payment Notification (IPN).
diff --git a/paypal/pro/admin.py b/paypal/pro/admin.py
index 5a9dc28..2b41b7f 100644
--- a/paypal/pro/admin.py
+++ b/paypal/pro/admin.py
@@ -6,7 +6,7 @@
class PayPalNVPAdmin(admin.ModelAdmin):
- list_display = ('user', 'ipaddress', 'method', 'flag', 'flag_code', 'created_at')
- list_filter = ('flag', 'created_at')
- search_fields = ('user__email', 'ip_address', 'flag', 'firstname', 'lastname')
+ list_display = ('user', 'ipaddress', 'method', 'flag', 'flag_code', 'created_at')
+ list_filter = ('flag', 'created_at')
+ search_fields = ('user__email', 'ip_address', 'flag', 'firstname', 'lastname')
admin.site.register(PayPalNVP, PayPalNVPAdmin)
diff --git a/paypal/pro/creditcard.py b/paypal/pro/creditcard.py
index d709c93..ea6b0da 100644
--- a/paypal/pro/creditcard.py
+++ b/paypal/pro/creditcard.py
@@ -2,68 +2,68 @@
# -*- coding: utf-8 -*-
"""
Adapted from:
- - http://www.djangosnippets.org/snippets/764/
- - http://www.satchmoproject.com/trac/browser/satchmo/trunk/satchmo/apps/satchmo_utils/views.py
- - http://tinyurl.com/shoppify-credit-cards
+ - http://www.djangosnippets.org/snippets/764/
+ - http://www.satchmoproject.com/trac/browser/satchmo/trunk/satchmo/apps/satchmo_utils/views.py
+ - http://tinyurl.com/shoppify-credit-cards
"""
import re
# Well known card regular expressions.
CARDS = {
- 'Visa': re.compile(r"^4\d{12}(\d{3})?$"),
- 'Mastercard': re.compile(r"^(5[1-5]\d{4}|677189)\d{10}$"),
- 'Dinersclub': re.compile(r"^3(0[0-5]|[68]\d)\d{11}$"),
- 'Amex': re.compile("^3[47]\d{13}$"),
- 'Discover': re.compile("^(6011|65\d{2})\d{12}$"),
+ 'Visa': re.compile(r"^4\d{12}(\d{3})?$"),
+ 'Mastercard': re.compile(r"^(5[1-5]\d{4}|677189)\d{10}$"),
+ 'Dinersclub': re.compile(r"^3(0[0-5]|[68]\d)\d{11}$"),
+ 'Amex': re.compile("^3[47]\d{13}$"),
+ 'Discover': re.compile("^(6011|65\d{2})\d{12}$"),
}
# Well known test numbers
TEST_NUMBERS = [
- "378282246310005", "371449635398431", "378734493671000", "30569309025904",
- "38520000023237", "6011111111111117", "6011000990139424", "555555555554444",
- "5105105105105100", "4111111111111111", "4012888888881881", "4222222222222"
+ "378282246310005", "371449635398431", "378734493671000", "30569309025904",
+ "38520000023237", "6011111111111117", "6011000990139424", "555555555554444",
+ "5105105105105100", "4111111111111111", "4012888888881881", "4222222222222"
]
def verify_credit_card(number):
- """Returns the card type for given card number or None if invalid."""
- return CreditCard(number).verify()
+ """Returns the card type for given card number or None if invalid."""
+ return CreditCard(number).verify()
class CreditCard(object):
- def __init__(self, number):
- self.number = number
+ def __init__(self, number):
+ self.number = number
- def is_number(self):
- """True if there is at least one digit in number."""
- self.number = re.sub(r'[^\d]', '', self.number)
- return self.number.isdigit()
+ def is_number(self):
+ """True if there is at least one digit in number."""
+ self.number = re.sub(r'[^\d]', '', self.number)
+ return self.number.isdigit()
- def is_mod10(self):
- """Returns True if number is valid according to mod10."""
- double = 0
- total = 0
- for i in range(len(self.number) - 1, -1, -1):
- for c in str((double + 1) * int(self.number[i])):
- total = total + int(c)
- double = (double + 1) % 2
- return (total % 10) == 0
+ def is_mod10(self):
+ """Returns True if number is valid according to mod10."""
+ double = 0
+ total = 0
+ for i in range(len(self.number) - 1, -1, -1):
+ for c in str((double + 1) * int(self.number[i])):
+ total = total + int(c)
+ double = (double + 1) % 2
+ return (total % 10) == 0
- def is_test(self):
- """Returns True if number is a test card number."""
- # Note: test numbers cannot be used in the PP Pro sandbox.
- # Instead, use the credit card number associated with a
- # sandbox account (Test Accounts -> View Details).
- return self.number in TEST_NUMBERS
+ def is_test(self):
+ """Returns True if number is a test card number."""
+ # Note: test numbers cannot be used in the PP Pro sandbox.
+ # Instead, use the credit card number associated with a
+ # sandbox account (Test Accounts -> View Details).
+ return self.number in TEST_NUMBERS
- def get_type(self):
- """Return the type if it matches one of the cards."""
- for card, pattern in CARDS.iteritems():
- if pattern.match(self.number):
- return card
- return None
+ def get_type(self):
+ """Return the type if it matches one of the cards."""
+ for card, pattern in CARDS.iteritems():
+ if pattern.match(self.number):
+ return card
+ return None
- def verify(self):
- """Returns the card type if valid else None."""
- if self.is_number() and not self.is_test() and self.is_mod10():
- return self.get_type()
- return None
+ def verify(self):
+ """Returns the card type if valid else None."""
+ if self.is_number() and not self.is_test() and self.is_mod10():
+ return self.get_type()
+ return None
diff --git a/paypal/pro/fields.py b/paypal/pro/fields.py
index 8b577a1..dbf4b41 100644
--- a/paypal/pro/fields.py
+++ b/paypal/pro/fields.py
@@ -11,333 +11,333 @@
class CreditCardField(forms.CharField):
- """Form field for checking out a credit card."""
- def __init__(self, *args, **kwargs):
- kwargs.setdefault('max_length', 20)
- super(CreditCardField, self).__init__(*args, **kwargs)
-
- def clean(self, value):
- """Raises a ValidationError if the card is not valid and stashes card type."""
- if value:
- value = value.replace('-', '').replace(' ', '')
- self.card_type = verify_credit_card(value)
- if self.card_type is None:
- raise forms.ValidationError("Invalid credit card number.")
- return value
+ """Form field for checking out a credit card."""
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('max_length', 20)
+ super(CreditCardField, self).__init__(*args, **kwargs)
+
+ def clean(self, value):
+ """Raises a ValidationError if the card is not valid and stashes card type."""
+ if value:
+ value = value.replace('-', '').replace(' ', '')
+ self.card_type = verify_credit_card(value)
+ if self.card_type is None:
+ raise forms.ValidationError("Invalid credit card number.")
+ return value
# Credit Card Expiry Fields from:
# http://www.djangosnippets.org/snippets/907/
class CreditCardExpiryWidget(forms.MultiWidget):
- """MultiWidget for representing credit card expiry date."""
- def decompress(self, value):
- if isinstance(value, date):
- return [value.month, value.year]
- elif isinstance(value, basestring):
- return [value[0:2], value[2:]]
- else:
- return [None, None]
+ """MultiWidget for representing credit card expiry date."""
+ def decompress(self, value):
+ if isinstance(value, date):
+ return [value.month, value.year]
+ elif isinstance(value, basestring):
+ return [value[0:2], value[2:]]
+ else:
+ return [None, None]
- def format_output(self, rendered_widgets):
- html = u' / '.join(rendered_widgets)
- return u'%s' % html
+ def format_output(self, rendered_widgets):
+ html = u' / '.join(rendered_widgets)
+ return u'%s' % html
class CreditCardExpiryField(forms.MultiValueField):
- EXP_MONTH = [(x, x) for x in xrange(1, 13)]
- EXP_YEAR = [(x, x) for x in xrange(date.today().year, date.today().year + 15)]
+ EXP_MONTH = [(x, x) for x in xrange(1, 13)]
+ EXP_YEAR = [(x, x) for x in xrange(date.today().year, date.today().year + 15)]
- default_error_messages = {
- 'invalid_month': u'Enter a valid month.',
- 'invalid_year': u'Enter a valid year.',
- }
+ default_error_messages = {
+ 'invalid_month': u'Enter a valid month.',
+ 'invalid_year': u'Enter a valid year.',
+ }
- def __init__(self, *args, **kwargs):
- errors = self.default_error_messages.copy()
- if 'error_messages' in kwargs:
- errors.update(kwargs['error_messages'])
-
- fields = (
- forms.ChoiceField(choices=self.EXP_MONTH, error_messages={'invalid': errors['invalid_month']}),
- forms.ChoiceField(choices=self.EXP_YEAR, error_messages={'invalid': errors['invalid_year']}),
- )
-
- super(CreditCardExpiryField, self).__init__(fields, *args, **kwargs)
- self.widget = CreditCardExpiryWidget(widgets=[fields[0].widget, fields[1].widget])
+ def __init__(self, *args, **kwargs):
+ errors = self.default_error_messages.copy()
+ if 'error_messages' in kwargs:
+ errors.update(kwargs['error_messages'])
+
+ fields = (
+ forms.ChoiceField(choices=self.EXP_MONTH, error_messages={'invalid': errors['invalid_month']}),
+ forms.ChoiceField(choices=self.EXP_YEAR, error_messages={'invalid': errors['invalid_year']}),
+ )
+
+ super(CreditCardExpiryField, self).__init__(fields, *args, **kwargs)
+ self.widget = CreditCardExpiryWidget(widgets=[fields[0].widget, fields[1].widget])
- def clean(self, value):
- exp = super(CreditCardExpiryField, self).clean(value)
- if date.today() > exp:
- raise forms.ValidationError("The expiration date you entered is in the past.")
- return exp
+ def clean(self, value):
+ exp = super(CreditCardExpiryField, self).clean(value)
+ if date.today() > exp:
+ raise forms.ValidationError("The expiration date you entered is in the past.")
+ return exp
- def compress(self, data_list):
- if data_list:
- if data_list[1] in forms.fields.EMPTY_VALUES:
- error = self.error_messages['invalid_year']
- raise forms.ValidationError(error)
- if data_list[0] in forms.fields.EMPTY_VALUES:
- error = self.error_messages['invalid_month']
- raise forms.ValidationError(error)
- year = int(data_list[1])
- month = int(data_list[0])
- # find last day of the month
- day = monthrange(year, month)[1]
- return date(year, month, day)
- return None
+ def compress(self, data_list):
+ if data_list:
+ if data_list[1] in forms.fields.EMPTY_VALUES:
+ error = self.error_messages['invalid_year']
+ raise forms.ValidationError(error)
+ if data_list[0] in forms.fields.EMPTY_VALUES:
+ error = self.error_messages['invalid_month']
+ raise forms.ValidationError(error)
+ year = int(data_list[1])
+ month = int(data_list[0])
+ # find last day of the month
+ day = monthrange(year, month)[1]
+ return date(year, month, day)
+ return None
class CreditCardCVV2Field(forms.CharField):
- def __init__(self, *args, **kwargs):
- kwargs.setdefault('max_length', 4)
- super(CreditCardCVV2Field, self).__init__(*args, **kwargs)
-
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('max_length', 4)
+ super(CreditCardCVV2Field, self).__init__(*args, **kwargs)
+
# Country Field from:
# http://www.djangosnippets.org/snippets/494/
# http://xml.coverpages.org/country3166.html
COUNTRIES = (
- ('US', _('United States of America')),
- ('CA', _('Canada')),
- ('AF', _('Afghanistan')),
- ('AL', _('Albania')),
- ('DZ', _('Algeria')),
- ('AS', _('American Samoa')),
- ('AD', _('Andorra')),
- ('AO', _('Angola')),
- ('AI', _('Anguilla')),
- ('AQ', _('Antarctica')),
- ('AG', _('Antigua & Barbuda')),
- ('AR', _('Argentina')),
- ('AM', _('Armenia')),
- ('AW', _('Aruba')),
- ('AU', _('Australia')),
- ('AT', _('Austria')),
- ('AZ', _('Azerbaijan')),
- ('BS', _('Bahama')),
- ('BH', _('Bahrain')),
- ('BD', _('Bangladesh')),
- ('BB', _('Barbados')),
- ('BY', _('Belarus')),
- ('BE', _('Belgium')),
- ('BZ', _('Belize')),
- ('BJ', _('Benin')),
- ('BM', _('Bermuda')),
- ('BT', _('Bhutan')),
- ('BO', _('Bolivia')),
- ('BA', _('Bosnia and Herzegovina')),
- ('BW', _('Botswana')),
- ('BV', _('Bouvet Island')),
- ('BR', _('Brazil')),
- ('IO', _('British Indian Ocean Territory')),
- ('VG', _('British Virgin Islands')),
- ('BN', _('Brunei Darussalam')),
- ('BG', _('Bulgaria')),
- ('BF', _('Burkina Faso')),
- ('BI', _('Burundi')),
- ('KH', _('Cambodia')),
- ('CM', _('Cameroon')),
- ('CV', _('Cape Verde')),
- ('KY', _('Cayman Islands')),
- ('CF', _('Central African Republic')),
- ('TD', _('Chad')),
- ('CL', _('Chile')),
- ('CN', _('China')),
- ('CX', _('Christmas Island')),
- ('CC', _('Cocos (Keeling) Islands')),
- ('CO', _('Colombia')),
- ('KM', _('Comoros')),
- ('CG', _('Congo')),
- ('CK', _('Cook Iislands')),
- ('CR', _('Costa Rica')),
- ('HR', _('Croatia')),
- ('CU', _('Cuba')),
- ('CY', _('Cyprus')),
- ('CZ', _('Czech Republic')),
- ('DK', _('Denmark')),
- ('DJ', _('Djibouti')),
- ('DM', _('Dominica')),
- ('DO', _('Dominican Republic')),
- ('TP', _('East Timor')),
- ('EC', _('Ecuador')),
- ('EG', _('Egypt')),
- ('SV', _('El Salvador')),
- ('GQ', _('Equatorial Guinea')),
- ('ER', _('Eritrea')),
- ('EE', _('Estonia')),
- ('ET', _('Ethiopia')),
- ('FK', _('Falkland Islands (Malvinas)')),
- ('FO', _('Faroe Islands')),
- ('FJ', _('Fiji')),
- ('FI', _('Finland')),
- ('FR', _('France')),
- ('FX', _('France, Metropolitan')),
- ('GF', _('French Guiana')),
- ('PF', _('French Polynesia')),
- ('TF', _('French Southern Territories')),
- ('GA', _('Gabon')),
- ('GM', _('Gambia')),
- ('GE', _('Georgia')),
- ('DE', _('Germany')),
- ('GH', _('Ghana')),
- ('GI', _('Gibraltar')),
- ('GR', _('Greece')),
- ('GL', _('Greenland')),
- ('GD', _('Grenada')),
- ('GP', _('Guadeloupe')),
- ('GU', _('Guam')),
- ('GT', _('Guatemala')),
- ('GN', _('Guinea')),
- ('GW', _('Guinea-Bissau')),
- ('GY', _('Guyana')),
- ('HT', _('Haiti')),
- ('HM', _('Heard & McDonald Islands')),
- ('HN', _('Honduras')),
- ('HK', _('Hong Kong')),
- ('HU', _('Hungary')),
- ('IS', _('Iceland')),
- ('IN', _('India')),
- ('ID', _('Indonesia')),
- ('IQ', _('Iraq')),
- ('IE', _('Ireland')),
- ('IR', _('Islamic Republic of Iran')),
- ('IL', _('Israel')),
- ('IT', _('Italy')),
- ('CI', _('Ivory Coast')),
- ('JM', _('Jamaica')),
- ('JP', _('Japan')),
- ('JO', _('Jordan')),
- ('KZ', _('Kazakhstan')),
- ('KE', _('Kenya')),
- ('KI', _('Kiribati')),
- ('KP', _('Korea, Democratic People\'s Republic of')),
- ('KR', _('Korea, Republic of')),
- ('KW', _('Kuwait')),
- ('KG', _('Kyrgyzstan')),
- ('LA', _('Lao People\'s Democratic Republic')),
- ('LV', _('Latvia')),
- ('LB', _('Lebanon')),
- ('LS', _('Lesotho')),
- ('LR', _('Liberia')),
- ('LY', _('Libyan Arab Jamahiriya')),
- ('LI', _('Liechtenstein')),
- ('LT', _('Lithuania')),
- ('LU', _('Luxembourg')),
- ('MO', _('Macau')),
- ('MG', _('Madagascar')),
- ('MW', _('Malawi')),
- ('MY', _('Malaysia')),
- ('MV', _('Maldives')),
- ('ML', _('Mali')),
- ('MT', _('Malta')),
- ('MH', _('Marshall Islands')),
- ('MQ', _('Martinique')),
- ('MR', _('Mauritania')),
- ('MU', _('Mauritius')),
- ('YT', _('Mayotte')),
- ('MX', _('Mexico')),
- ('FM', _('Micronesia')),
- ('MD', _('Moldova, Republic of')),
- ('MC', _('Monaco')),
- ('MN', _('Mongolia')),
- ('MS', _('Monserrat')),
- ('MA', _('Morocco')),
- ('MZ', _('Mozambique')),
- ('MM', _('Myanmar')),
- ('NA', _('Namibia')),
- ('NR', _('Nauru')),
- ('NP', _('Nepal')),
- ('NL', _('Netherlands')),
- ('AN', _('Netherlands Antilles')),
- ('NC', _('New Caledonia')),
- ('NZ', _('New Zealand')),
- ('NI', _('Nicaragua')),
- ('NE', _('Niger')),
- ('NG', _('Nigeria')),
- ('NU', _('Niue')),
- ('NF', _('Norfolk Island')),
- ('MP', _('Northern Mariana Islands')),
- ('NO', _('Norway')),
- ('OM', _('Oman')),
- ('PK', _('Pakistan')),
- ('PW', _('Palau')),
- ('PA', _('Panama')),
- ('PG', _('Papua New Guinea')),
- ('PY', _('Paraguay')),
- ('PE', _('Peru')),
- ('PH', _('Philippines')),
- ('PN', _('Pitcairn')),
- ('PL', _('Poland')),
- ('PT', _('Portugal')),
- ('PR', _('Puerto Rico')),
- ('QA', _('Qatar')),
- ('RE', _('Reunion')),
- ('RO', _('Romania')),
- ('RU', _('Russian Federation')),
- ('RW', _('Rwanda')),
- ('LC', _('Saint Lucia')),
- ('WS', _('Samoa')),
- ('SM', _('San Marino')),
- ('ST', _('Sao Tome & Principe')),
- ('SA', _('Saudi Arabia')),
- ('SN', _('Senegal')),
- ('SC', _('Seychelles')),
- ('SL', _('Sierra Leone')),
- ('SG', _('Singapore')),
- ('SK', _('Slovakia')),
- ('SI', _('Slovenia')),
- ('SB', _('Solomon Islands')),
- ('SO', _('Somalia')),
- ('ZA', _('South Africa')),
- ('GS', _('South Georgia and the South Sandwich Islands')),
- ('ES', _('Spain')),
- ('LK', _('Sri Lanka')),
- ('SH', _('St. Helena')),
- ('KN', _('St. Kitts and Nevis')),
- ('PM', _('St. Pierre & Miquelon')),
- ('VC', _('St. Vincent & the Grenadines')),
- ('SD', _('Sudan')),
- ('SR', _('Suriname')),
- ('SJ', _('Svalbard & Jan Mayen Islands')),
- ('SZ', _('Swaziland')),
- ('SE', _('Sweden')),
- ('CH', _('Switzerland')),
- ('SY', _('Syrian Arab Republic')),
- ('TW', _('Taiwan, Province of China')),
- ('TJ', _('Tajikistan')),
- ('TZ', _('Tanzania, United Republic of')),
- ('TH', _('Thailand')),
- ('TG', _('Togo')),
- ('TK', _('Tokelau')),
- ('TO', _('Tonga')),
- ('TT', _('Trinidad & Tobago')),
- ('TN', _('Tunisia')),
- ('TR', _('Turkey')),
- ('TM', _('Turkmenistan')),
- ('TC', _('Turks & Caicos Islands')),
- ('TV', _('Tuvalu')),
- ('UG', _('Uganda')),
- ('UA', _('Ukraine')),
- ('AE', _('United Arab Emirates')),
- ('GB', _('United Kingdom (Great Britain)')),
- ('UM', _('United States Minor Outlying Islands')),
- ('VI', _('United States Virgin Islands')),
- ('ZZ', _('Unknown or unspecified country')),
- ('UY', _('Uruguay')),
- ('UZ', _('Uzbekistan')),
- ('VU', _('Vanuatu')),
- ('VA', _('Vatican City State (Holy See)')),
- ('VE', _('Venezuela')),
- ('VN', _('Viet Nam')),
- ('WF', _('Wallis & Futuna Islands')),
- ('EH', _('Western Sahara')),
- ('YE', _('Yemen')),
- ('YU', _('Yugoslavia')),
- ('ZR', _('Zaire')),
- ('ZM', _('Zambia')),
- ('ZW', _('Zimbabwe')),
+ ('US', _('United States of America')),
+ ('CA', _('Canada')),
+ ('AF', _('Afghanistan')),
+ ('AL', _('Albania')),
+ ('DZ', _('Algeria')),
+ ('AS', _('American Samoa')),
+ ('AD', _('Andorra')),
+ ('AO', _('Angola')),
+ ('AI', _('Anguilla')),
+ ('AQ', _('Antarctica')),
+ ('AG', _('Antigua & Barbuda')),
+ ('AR', _('Argentina')),
+ ('AM', _('Armenia')),
+ ('AW', _('Aruba')),
+ ('AU', _('Australia')),
+ ('AT', _('Austria')),
+ ('AZ', _('Azerbaijan')),
+ ('BS', _('Bahama')),
+ ('BH', _('Bahrain')),
+ ('BD', _('Bangladesh')),
+ ('BB', _('Barbados')),
+ ('BY', _('Belarus')),
+ ('BE', _('Belgium')),
+ ('BZ', _('Belize')),
+ ('BJ', _('Benin')),
+ ('BM', _('Bermuda')),
+ ('BT', _('Bhutan')),
+ ('BO', _('Bolivia')),
+ ('BA', _('Bosnia and Herzegovina')),
+ ('BW', _('Botswana')),
+ ('BV', _('Bouvet Island')),
+ ('BR', _('Brazil')),
+ ('IO', _('British Indian Ocean Territory')),
+ ('VG', _('British Virgin Islands')),
+ ('BN', _('Brunei Darussalam')),
+ ('BG', _('Bulgaria')),
+ ('BF', _('Burkina Faso')),
+ ('BI', _('Burundi')),
+ ('KH', _('Cambodia')),
+ ('CM', _('Cameroon')),
+ ('CV', _('Cape Verde')),
+ ('KY', _('Cayman Islands')),
+ ('CF', _('Central African Republic')),
+ ('TD', _('Chad')),
+ ('CL', _('Chile')),
+ ('CN', _('China')),
+ ('CX', _('Christmas Island')),
+ ('CC', _('Cocos (Keeling) Islands')),
+ ('CO', _('Colombia')),
+ ('KM', _('Comoros')),
+ ('CG', _('Congo')),
+ ('CK', _('Cook Iislands')),
+ ('CR', _('Costa Rica')),
+ ('HR', _('Croatia')),
+ ('CU', _('Cuba')),
+ ('CY', _('Cyprus')),
+ ('CZ', _('Czech Republic')),
+ ('DK', _('Denmark')),
+ ('DJ', _('Djibouti')),
+ ('DM', _('Dominica')),
+ ('DO', _('Dominican Republic')),
+ ('TP', _('East Timor')),
+ ('EC', _('Ecuador')),
+ ('EG', _('Egypt')),
+ ('SV', _('El Salvador')),
+ ('GQ', _('Equatorial Guinea')),
+ ('ER', _('Eritrea')),
+ ('EE', _('Estonia')),
+ ('ET', _('Ethiopia')),
+ ('FK', _('Falkland Islands (Malvinas)')),
+ ('FO', _('Faroe Islands')),
+ ('FJ', _('Fiji')),
+ ('FI', _('Finland')),
+ ('FR', _('France')),
+ ('FX', _('France, Metropolitan')),
+ ('GF', _('French Guiana')),
+ ('PF', _('French Polynesia')),
+ ('TF', _('French Southern Territories')),
+ ('GA', _('Gabon')),
+ ('GM', _('Gambia')),
+ ('GE', _('Georgia')),
+ ('DE', _('Germany')),
+ ('GH', _('Ghana')),
+ ('GI', _('Gibraltar')),
+ ('GR', _('Greece')),
+ ('GL', _('Greenland')),
+ ('GD', _('Grenada')),
+ ('GP', _('Guadeloupe')),
+ ('GU', _('Guam')),
+ ('GT', _('Guatemala')),
+ ('GN', _('Guinea')),
+ ('GW', _('Guinea-Bissau')),
+ ('GY', _('Guyana')),
+ ('HT', _('Haiti')),
+ ('HM', _('Heard & McDonald Islands')),
+ ('HN', _('Honduras')),
+ ('HK', _('Hong Kong')),
+ ('HU', _('Hungary')),
+ ('IS', _('Iceland')),
+ ('IN', _('India')),
+ ('ID', _('Indonesia')),
+ ('IQ', _('Iraq')),
+ ('IE', _('Ireland')),
+ ('IR', _('Islamic Republic of Iran')),
+ ('IL', _('Israel')),
+ ('IT', _('Italy')),
+ ('CI', _('Ivory Coast')),
+ ('JM', _('Jamaica')),
+ ('JP', _('Japan')),
+ ('JO', _('Jordan')),
+ ('KZ', _('Kazakhstan')),
+ ('KE', _('Kenya')),
+ ('KI', _('Kiribati')),
+ ('KP', _('Korea, Democratic People\'s Republic of')),
+ ('KR', _('Korea, Republic of')),
+ ('KW', _('Kuwait')),
+ ('KG', _('Kyrgyzstan')),
+ ('LA', _('Lao People\'s Democratic Republic')),
+ ('LV', _('Latvia')),
+ ('LB', _('Lebanon')),
+ ('LS', _('Lesotho')),
+ ('LR', _('Liberia')),
+ ('LY', _('Libyan Arab Jamahiriya')),
+ ('LI', _('Liechtenstein')),
+ ('LT', _('Lithuania')),
+ ('LU', _('Luxembourg')),
+ ('MO', _('Macau')),
+ ('MG', _('Madagascar')),
+ ('MW', _('Malawi')),
+ ('MY', _('Malaysia')),
+ ('MV', _('Maldives')),
+ ('ML', _('Mali')),
+ ('MT', _('Malta')),
+ ('MH', _('Marshall Islands')),
+ ('MQ', _('Martinique')),
+ ('MR', _('Mauritania')),
+ ('MU', _('Mauritius')),
+ ('YT', _('Mayotte')),
+ ('MX', _('Mexico')),
+ ('FM', _('Micronesia')),
+ ('MD', _('Moldova, Republic of')),
+ ('MC', _('Monaco')),
+ ('MN', _('Mongolia')),
+ ('MS', _('Monserrat')),
+ ('MA', _('Morocco')),
+ ('MZ', _('Mozambique')),
+ ('MM', _('Myanmar')),
+ ('NA', _('Namibia')),
+ ('NR', _('Nauru')),
+ ('NP', _('Nepal')),
+ ('NL', _('Netherlands')),
+ ('AN', _('Netherlands Antilles')),
+ ('NC', _('New Caledonia')),
+ ('NZ', _('New Zealand')),
+ ('NI', _('Nicaragua')),
+ ('NE', _('Niger')),
+ ('NG', _('Nigeria')),
+ ('NU', _('Niue')),
+ ('NF', _('Norfolk Island')),
+ ('MP', _('Northern Mariana Islands')),
+ ('NO', _('Norway')),
+ ('OM', _('Oman')),
+ ('PK', _('Pakistan')),
+ ('PW', _('Palau')),
+ ('PA', _('Panama')),
+ ('PG', _('Papua New Guinea')),
+ ('PY', _('Paraguay')),
+ ('PE', _('Peru')),
+ ('PH', _('Philippines')),
+ ('PN', _('Pitcairn')),
+ ('PL', _('Poland')),
+ ('PT', _('Portugal')),
+ ('PR', _('Puerto Rico')),
+ ('QA', _('Qatar')),
+ ('RE', _('Reunion')),
+ ('RO', _('Romania')),
+ ('RU', _('Russian Federation')),
+ ('RW', _('Rwanda')),
+ ('LC', _('Saint Lucia')),
+ ('WS', _('Samoa')),
+ ('SM', _('San Marino')),
+ ('ST', _('Sao Tome & Principe')),
+ ('SA', _('Saudi Arabia')),
+ ('SN', _('Senegal')),
+ ('SC', _('Seychelles')),
+ ('SL', _('Sierra Leone')),
+ ('SG', _('Singapore')),
+ ('SK', _('Slovakia')),
+ ('SI', _('Slovenia')),
+ ('SB', _('Solomon Islands')),
+ ('SO', _('Somalia')),
+ ('ZA', _('South Africa')),
+ ('GS', _('South Georgia and the South Sandwich Islands')),
+ ('ES', _('Spain')),
+ ('LK', _('Sri Lanka')),
+ ('SH', _('St. Helena')),
+ ('KN', _('St. Kitts and Nevis')),
+ ('PM', _('St. Pierre & Miquelon')),
+ ('VC', _('St. Vincent & the Grenadines')),
+ ('SD', _('Sudan')),
+ ('SR', _('Suriname')),
+ ('SJ', _('Svalbard & Jan Mayen Islands')),
+ ('SZ', _('Swaziland')),
+ ('SE', _('Sweden')),
+ ('CH', _('Switzerland')),
+ ('SY', _('Syrian Arab Republic')),
+ ('TW', _('Taiwan, Province of China')),
+ ('TJ', _('Tajikistan')),
+ ('TZ', _('Tanzania, United Republic of')),
+ ('TH', _('Thailand')),
+ ('TG', _('Togo')),
+ ('TK', _('Tokelau')),
+ ('TO', _('Tonga')),
+ ('TT', _('Trinidad & Tobago')),
+ ('TN', _('Tunisia')),
+ ('TR', _('Turkey')),
+ ('TM', _('Turkmenistan')),
+ ('TC', _('Turks & Caicos Islands')),
+ ('TV', _('Tuvalu')),
+ ('UG', _('Uganda')),
+ ('UA', _('Ukraine')),
+ ('AE', _('United Arab Emirates')),
+ ('GB', _('United Kingdom (Great Britain)')),
+ ('UM', _('United States Minor Outlying Islands')),
+ ('VI', _('United States Virgin Islands')),
+ ('ZZ', _('Unknown or unspecified country')),
+ ('UY', _('Uruguay')),
+ ('UZ', _('Uzbekistan')),
+ ('VU', _('Vanuatu')),
+ ('VA', _('Vatican City State (Holy See)')),
+ ('VE', _('Venezuela')),
+ ('VN', _('Viet Nam')),
+ ('WF', _('Wallis & Futuna Islands')),
+ ('EH', _('Western Sahara')),
+ ('YE', _('Yemen')),
+ ('YU', _('Yugoslavia')),
+ ('ZR', _('Zaire')),
+ ('ZM', _('Zambia')),
+ ('ZW', _('Zimbabwe')),
)
class CountryField(forms.ChoiceField):
- def __init__(self, *args, **kwargs):
- kwargs.setdefault('choices', COUNTRIES)
- super(CountryField, self).__init__(*args, **kwargs)
\ No newline at end of file
+ def __init__(self, *args, **kwargs):
+ kwargs.setdefault('choices', COUNTRIES)
+ super(CountryField, self).__init__(*args, **kwargs)
\ No newline at end of file
diff --git a/paypal/pro/forms.py b/paypal/pro/forms.py
index 42418f3..85db249 100644
--- a/paypal/pro/forms.py
+++ b/paypal/pro/forms.py
@@ -6,40 +6,40 @@
from paypal.pro.exceptions import PayPalFailure
class PaymentForm(forms.Form):
- """Form used to process direct payments."""
- firstname = forms.CharField(255, label="First Name")
- lastname = forms.CharField(255, label="Last Name")
- street = forms.CharField(255, label="Street Address")
- city = forms.CharField(255, label="City")
- state = forms.CharField(255, label="State")
- countrycode = CountryField(label="Country", initial="US")
- zip = forms.CharField(32, label="Postal / Zip Code")
- acct = CreditCardField(label="Credit Card Number")
- expdate = CreditCardExpiryField(label="Expiration Date")
- cvv2 = CreditCardCVV2Field(label="Card Security Code")
+ """Form used to process direct payments."""
+ firstname = forms.CharField(255, label="First Name")
+ lastname = forms.CharField(255, label="Last Name")
+ street = forms.CharField(255, label="Street Address")
+ city = forms.CharField(255, label="City")
+ state = forms.CharField(255, label="State")
+ countrycode = CountryField(label="Country", initial="US")
+ zip = forms.CharField(32, label="Postal / Zip Code")
+ acct = CreditCardField(label="Credit Card Number")
+ expdate = CreditCardExpiryField(label="Expiration Date")
+ cvv2 = CreditCardCVV2Field(label="Card Security Code")
- def process(self, request, item):
- """Process a PayPal direct payment."""
- from paypal.pro.helpers import PayPalWPP
- wpp = PayPalWPP(request)
- params = self.cleaned_data
- params['creditcardtype'] = self.fields['acct'].card_type
- params['expdate'] = self.cleaned_data['expdate'].strftime("%m%Y")
- params['ipaddress'] = request.META.get("REMOTE_ADDR", "")
- params.update(item)
+ def process(self, request, item):
+ """Process a PayPal direct payment."""
+ from paypal.pro.helpers import PayPalWPP
+ wpp = PayPalWPP(request)
+ params = self.cleaned_data
+ params['creditcardtype'] = self.fields['acct'].card_type
+ params['expdate'] = self.cleaned_data['expdate'].strftime("%m%Y")
+ params['ipaddress'] = request.META.get("REMOTE_ADDR", "")
+ params.update(item)
- try:
- # Create single payment:
- if 'billingperiod' not in params:
- nvp_obj = wpp.doDirectPayment(params)
- # Create recurring payment:
- else:
- nvp_obj = wpp.createRecurringPaymentsProfile(params, direct=True)
- except PayPalFailure:
- return False
- return True
+ try:
+ # Create single payment:
+ if 'billingperiod' not in params:
+ nvp_obj = wpp.doDirectPayment(params)
+ # Create recurring payment:
+ else:
+ nvp_obj = wpp.createRecurringPaymentsProfile(params, direct=True)
+ except PayPalFailure:
+ return False
+ return True
class ConfirmForm(forms.Form):
- """Hidden form used by ExpressPay flow to keep track of payer information."""
- token = forms.CharField(max_length=255, widget=forms.HiddenInput())
- PayerID = forms.CharField(max_length=255, widget=forms.HiddenInput())
\ No newline at end of file
+ """Hidden form used by ExpressPay flow to keep track of payer information."""
+ token = forms.CharField(max_length=255, widget=forms.HiddenInput())
+ PayerID = forms.CharField(max_length=255, widget=forms.HiddenInput())
\ No newline at end of file
diff --git a/paypal/pro/helpers.py b/paypal/pro/helpers.py
index 4942bf2..e6e4ad7 100644
--- a/paypal/pro/helpers.py
+++ b/paypal/pro/helpers.py
@@ -28,238 +28,238 @@
def paypal_time(time_obj=None):
- """Returns a time suitable for PayPal time fields."""
- if time_obj is None:
- time_obj = time.gmtime()
- return time.strftime(PayPalNVP.TIMESTAMP_FORMAT, time_obj)
-
+ """Returns a time suitable for PayPal time fields."""
+ if time_obj is None:
+ time_obj = time.gmtime()
+ return time.strftime(PayPalNVP.TIMESTAMP_FORMAT, time_obj)
+
def paypaltime2datetime(s):
- """Convert a PayPal time string to a DateTime."""
- return datetime.datetime(*(time.strptime(s, PayPalNVP.TIMESTAMP_FORMAT)[:6]))
+ """Convert a PayPal time string to a DateTime."""
+ return datetime.datetime(*(time.strptime(s, PayPalNVP.TIMESTAMP_FORMAT)[:6]))
class PayPalError(TypeError):
- """Error thrown when something be wrong."""
-
+ """Error thrown when something be wrong."""
+
class PayPalWPP(object):
- """
- Wrapper class for the PayPal Website Payments Pro.
-
- Website Payments Pro Integration Guide:
- https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_WPP_IntegrationGuide.pdf
-
- Name-Value Pair API Developer Guide and Reference:
- https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_NVPAPI_DeveloperGuide.pdf
- """
- def __init__(self, request, params=BASE_PARAMS):
- """Required - USER / PWD / SIGNATURE / VERSION"""
- self.request = request
- if TEST:
- self.endpoint = SANDBOX_ENDPOINT
- else:
- self.endpoint = ENDPOINT
- self.signature_values = params
- self.signature = urlencode(self.signature_values) + "&"
-
- def doDirectPayment(self, params):
- """Call PayPal DoDirectPayment method."""
- defaults = {"method": "DoDirectPayment", "paymentaction": "Sale"}
- required = L("creditcardtype acct expdate cvv2 ipaddress firstname lastname street city state countrycode zip amt")
- nvp_obj = self._fetch(params, required, defaults)
- if nvp_obj.flag:
- raise PayPalFailure(nvp_obj.flag_info)
- payment_was_successful.send(params)
- # @@@ Could check cvv2match / avscode are both 'X' or '0'
- # qd = django.http.QueryDict(nvp_obj.response)
- # if qd.get('cvv2match') not in ['X', '0']:
- # nvp_obj.set_flag("Invalid cvv2match: %s" % qd.get('cvv2match')
- # if qd.get('avscode') not in ['X', '0']:
- # nvp_obj.set_flag("Invalid avscode: %s" % qd.get('avscode')
- return nvp_obj
-
- def setExpressCheckout(self, params):
- """
- Initiates an Express Checkout transaction.
- Optionally, the SetExpressCheckout API operation can set up billing agreements for
- reference transactions and recurring payments.
- Returns a NVP instance - check for token and payerid to continue!
- """
- if self._is_recurring(params):
- params = self._recurring_setExpressCheckout_adapter(params)
-
- defaults = {"method": "SetExpressCheckout", "noshipping": 1}
- required = L("returnurl cancelurl amt")
- nvp_obj = self._fetch(params, required, defaults)
- if nvp_obj.flag:
- raise PayPalFailure(nvp_obj.flag_info)
- return nvp_obj
-
- def doExpressCheckoutPayment(self, params):
- """
- Check the dude out:
- """
- defaults = {"method": "DoExpressCheckoutPayment", "paymentaction": "Sale"}
- required = L("returnurl cancelurl amt token payerid")
- nvp_obj = self._fetch(params, required, defaults)
- if nvp_obj.flag:
- raise PayPalFailure(nvp_obj.flag_info)
- payment_was_successful.send(params)
- return nvp_obj
-
- def createRecurringPaymentsProfile(self, params, direct=False):
- """
- Set direct to True to indicate that this is being called as a directPayment.
- Returns True PayPal successfully creates the profile otherwise False.
- """
- defaults = {"method": "CreateRecurringPaymentsProfile"}
- required = L("profilestartdate billingperiod billingfrequency amt")
-
- # Direct payments require CC data
- if direct:
- required + L("creditcardtype acct expdate firstname lastname")
- else:
- required + L("token payerid")
-
- nvp_obj = self._fetch(params, required, defaults)
-
- # Flag if profile_type != ActiveProfile
- if nvp_obj.flag:
- raise PayPalFailure(nvp_obj.flag_info)
- payment_profile_created.send(params)
- return nvp_obj
-
- def getExpressCheckoutDetails(self, params):
- defaults = {"method": "GetExpressCheckoutDetails"}
- required = L("token")
- nvp_obj = self._fetch(params, required, defaults)
- if nvp_obj.flag:
- raise PayPalFailure(nvp_obj.flag_info)
- return nvp_obj
-
- def setCustomerBillingAgreement(self, params):
- raise DeprecationWarning
-
- def getTransactionDetails(self, params):
- defaults = {"method": "GetTransactionDetails"}
- required = L("transactionid")
-
- nvp_obj = self._fetch(params, required, defaults)
- if nvp_obj.flag:
- raise PayPalFailure(nvp_obj.flag_info)
- return nvp_obj
-
- def massPay(self, params):
- raise NotImplementedError
-
- def getRecurringPaymentsProfileDetails(self, params):
- raise NotImplementedError
-
- def updateRecurringPaymentsProfile(self, params):
- defaults = {"method": "UpdateRecurringPaymentsProfile"}
- required = L("profileid")
-
- nvp_obj = self._fetch(params, required, defaults)
- if nvp_obj.flag:
- raise PayPalFailure(nvp_obj.flag_info)
- return nvp_obj
-
- def billOutstandingAmount(self, params):
- raise NotImplementedError
-
- def manangeRecurringPaymentsProfileStatus(self, params, fail_silently=False):
- """
- Requires `profileid` and `action` params.
- Action must be either "Cancel", "Suspend", or "Reactivate".
- """
- defaults = {"method": "ManageRecurringPaymentsProfileStatus"}
- required = L("profileid action")
-
- nvp_obj = self._fetch(params, required, defaults)
-
- # TODO: This fail silently check should be using the error code, but its not easy to access
- if not nvp_obj.flag or (fail_silently and nvp_obj.flag_info == 'Invalid profile status for cancel action; profile should be active or suspended'):
- if params['action'] == 'Cancel':
- recurring_cancel.send(sender=nvp_obj)
- elif params['action'] == 'Suspend':
- recurring_suspend.send(sender=nvp_obj)
- elif params['action'] == 'Reactivate':
- recurring_reactivate.send(sender=nvp_obj)
- else:
- raise PayPalFailure(nvp_obj.flag_info)
- return nvp_obj
-
- def refundTransaction(self, params):
- raise NotImplementedError
-
- def _is_recurring(self, params):
- """Returns True if the item passed is a recurring transaction."""
- return 'billingfrequency' in params
-
- def _recurring_setExpressCheckout_adapter(self, params):
- """
- The recurring payment interface to SEC is different than the recurring payment
- interface to ECP. This adapts a normal call to look like a SEC call.
- """
- params['l_billingtype0'] = "RecurringPayments"
- params['l_billingagreementdescription0'] = params['desc']
-
- REMOVE = L("billingfrequency billingperiod profilestartdate desc")
- for k in params.keys():
- if k in REMOVE:
- del params[k]
-
- return params
-
- def _fetch(self, params, required, defaults):
- """Make the NVP request and store the response."""
- defaults.update(params)
- pp_params = self._check_and_update_params(required, defaults)
- pp_string = self.signature + urlencode(pp_params)
- response = self._request(pp_string)
- response_params = self._parse_response(response)
-
- if getattr(settings, 'PAYPAL_DEBUG', settings.DEBUG):
- print 'PayPal Request:'
- pprint.pprint(defaults)
- print '\nPayPal Response:'
- pprint.pprint(response_params)
-
- # Gather all NVP parameters to pass to a new instance.
- nvp_params = {}
- for k, v in MergeDict(defaults, response_params).items():
- if k in NVP_FIELDS:
- nvp_params[str(k)] = v
-
- # PayPal timestamp has to be formatted.
- if 'timestamp' in nvp_params:
- nvp_params['timestamp'] = paypaltime2datetime(nvp_params['timestamp'])
-
- nvp_obj = PayPalNVP(**nvp_params)
- nvp_obj.init(self.request, params, response_params)
- nvp_obj.save()
- return nvp_obj
-
- def _request(self, data):
- """Moved out to make testing easier."""
- return urllib2.urlopen(self.endpoint, data).read()
-
- def _check_and_update_params(self, required, params):
- """
- Ensure all required parameters were passed to the API call and format
- them correctly.
- """
- for r in required:
- if r not in params:
- raise PayPalError("Missing required param: %s" % r)
-
- # Upper case all the parameters for PayPal.
- return (dict((k.upper(), v) for k, v in params.iteritems()))
-
- def _parse_response(self, response):
- """Turn the PayPal response into a dict"""
- response_tokens = {}
- for kv in response.split('&'):
- key, value = kv.split("=")
- response_tokens[key.lower()] = urllib.unquote(value)
- return response_tokens
\ No newline at end of file
+ """
+ Wrapper class for the PayPal Website Payments Pro.
+
+ Website Payments Pro Integration Guide:
+ https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_WPP_IntegrationGuide.pdf
+
+ Name-Value Pair API Developer Guide and Reference:
+ https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_NVPAPI_DeveloperGuide.pdf
+ """
+ def __init__(self, request, params=BASE_PARAMS):
+ """Required - USER / PWD / SIGNATURE / VERSION"""
+ self.request = request
+ if TEST:
+ self.endpoint = SANDBOX_ENDPOINT
+ else:
+ self.endpoint = ENDPOINT
+ self.signature_values = params
+ self.signature = urlencode(self.signature_values) + "&"
+
+ def doDirectPayment(self, params):
+ """Call PayPal DoDirectPayment method."""
+ defaults = {"method": "DoDirectPayment", "paymentaction": "Sale"}
+ required = L("creditcardtype acct expdate cvv2 ipaddress firstname lastname street city state countrycode zip amt")
+ nvp_obj = self._fetch(params, required, defaults)
+ if nvp_obj.flag:
+ raise PayPalFailure(nvp_obj.flag_info)
+ payment_was_successful.send(params)
+ # @@@ Could check cvv2match / avscode are both 'X' or '0'
+ # qd = django.http.QueryDict(nvp_obj.response)
+ # if qd.get('cvv2match') not in ['X', '0']:
+ # nvp_obj.set_flag("Invalid cvv2match: %s" % qd.get('cvv2match')
+ # if qd.get('avscode') not in ['X', '0']:
+ # nvp_obj.set_flag("Invalid avscode: %s" % qd.get('avscode')
+ return nvp_obj
+
+ def setExpressCheckout(self, params):
+ """
+ Initiates an Express Checkout transaction.
+ Optionally, the SetExpressCheckout API operation can set up billing agreements for
+ reference transactions and recurring payments.
+ Returns a NVP instance - check for token and payerid to continue!
+ """
+ if self._is_recurring(params):
+ params = self._recurring_setExpressCheckout_adapter(params)
+
+ defaults = {"method": "SetExpressCheckout", "noshipping": 1}
+ required = L("returnurl cancelurl amt")
+ nvp_obj = self._fetch(params, required, defaults)
+ if nvp_obj.flag:
+ raise PayPalFailure(nvp_obj.flag_info)
+ return nvp_obj
+
+ def doExpressCheckoutPayment(self, params):
+ """
+ Check the dude out:
+ """
+ defaults = {"method": "DoExpressCheckoutPayment", "paymentaction": "Sale"}
+ required = L("returnurl cancelurl amt token payerid")
+ nvp_obj = self._fetch(params, required, defaults)
+ if nvp_obj.flag:
+ raise PayPalFailure(nvp_obj.flag_info)
+ payment_was_successful.send(params)
+ return nvp_obj
+
+ def createRecurringPaymentsProfile(self, params, direct=False):
+ """
+ Set direct to True to indicate that this is being called as a directPayment.
+ Returns True PayPal successfully creates the profile otherwise False.
+ """
+ defaults = {"method": "CreateRecurringPaymentsProfile"}
+ required = L("profilestartdate billingperiod billingfrequency amt")
+
+ # Direct payments require CC data
+ if direct:
+ required + L("creditcardtype acct expdate firstname lastname")
+ else:
+ required + L("token payerid")
+
+ nvp_obj = self._fetch(params, required, defaults)
+
+ # Flag if profile_type != ActiveProfile
+ if nvp_obj.flag:
+ raise PayPalFailure(nvp_obj.flag_info)
+ payment_profile_created.send(params)
+ return nvp_obj
+
+ def getExpressCheckoutDetails(self, params):
+ defaults = {"method": "GetExpressCheckoutDetails"}
+ required = L("token")
+ nvp_obj = self._fetch(params, required, defaults)
+ if nvp_obj.flag:
+ raise PayPalFailure(nvp_obj.flag_info)
+ return nvp_obj
+
+ def setCustomerBillingAgreement(self, params):
+ raise DeprecationWarning
+
+ def getTransactionDetails(self, params):
+ defaults = {"method": "GetTransactionDetails"}
+ required = L("transactionid")
+
+ nvp_obj = self._fetch(params, required, defaults)
+ if nvp_obj.flag:
+ raise PayPalFailure(nvp_obj.flag_info)
+ return nvp_obj
+
+ def massPay(self, params):
+ raise NotImplementedError
+
+ def getRecurringPaymentsProfileDetails(self, params):
+ raise NotImplementedError
+
+ def updateRecurringPaymentsProfile(self, params):
+ defaults = {"method": "UpdateRecurringPaymentsProfile"}
+ required = L("profileid")
+
+ nvp_obj = self._fetch(params, required, defaults)
+ if nvp_obj.flag:
+ raise PayPalFailure(nvp_obj.flag_info)
+ return nvp_obj
+
+ def billOutstandingAmount(self, params):
+ raise NotImplementedError
+
+ def manangeRecurringPaymentsProfileStatus(self, params, fail_silently=False):
+ """
+ Requires `profileid` and `action` params.
+ Action must be either "Cancel", "Suspend", or "Reactivate".
+ """
+ defaults = {"method": "ManageRecurringPaymentsProfileStatus"}
+ required = L("profileid action")
+
+ nvp_obj = self._fetch(params, required, defaults)
+
+ # TODO: This fail silently check should be using the error code, but its not easy to access
+ if not nvp_obj.flag or (fail_silently and nvp_obj.flag_info == 'Invalid profile status for cancel action; profile should be active or suspended'):
+ if params['action'] == 'Cancel':
+ recurring_cancel.send(sender=nvp_obj)
+ elif params['action'] == 'Suspend':
+ recurring_suspend.send(sender=nvp_obj)
+ elif params['action'] == 'Reactivate':
+ recurring_reactivate.send(sender=nvp_obj)
+ else:
+ raise PayPalFailure(nvp_obj.flag_info)
+ return nvp_obj
+
+ def refundTransaction(self, params):
+ raise NotImplementedError
+
+ def _is_recurring(self, params):
+ """Returns True if the item passed is a recurring transaction."""
+ return 'billingfrequency' in params
+
+ def _recurring_setExpressCheckout_adapter(self, params):
+ """
+ The recurring payment interface to SEC is different than the recurring payment
+ interface to ECP. This adapts a normal call to look like a SEC call.
+ """
+ params['l_billingtype0'] = "RecurringPayments"
+ params['l_billingagreementdescription0'] = params['desc']
+
+ REMOVE = L("billingfrequency billingperiod profilestartdate desc")
+ for k in params.keys():
+ if k in REMOVE:
+ del params[k]
+
+ return params
+
+ def _fetch(self, params, required, defaults):
+ """Make the NVP request and store the response."""
+ defaults.update(params)
+ pp_params = self._check_and_update_params(required, defaults)
+ pp_string = self.signature + urlencode(pp_params)
+ response = self._request(pp_string)
+ response_params = self._parse_response(response)
+
+ if getattr(settings, 'PAYPAL_DEBUG', settings.DEBUG):
+ print 'PayPal Request:'
+ pprint.pprint(defaults)
+ print '\nPayPal Response:'
+ pprint.pprint(response_params)
+
+ # Gather all NVP parameters to pass to a new instance.
+ nvp_params = {}
+ for k, v in MergeDict(defaults, response_params).items():
+ if k in NVP_FIELDS:
+ nvp_params[str(k)] = v
+
+ # PayPal timestamp has to be formatted.
+ if 'timestamp' in nvp_params:
+ nvp_params['timestamp'] = paypaltime2datetime(nvp_params['timestamp'])
+
+ nvp_obj = PayPalNVP(**nvp_params)
+ nvp_obj.init(self.request, params, response_params)
+ nvp_obj.save()
+ return nvp_obj
+
+ def _request(self, data):
+ """Moved out to make testing easier."""
+ return urllib2.urlopen(self.endpoint, data).read()
+
+ def _check_and_update_params(self, required, params):
+ """
+ Ensure all required parameters were passed to the API call and format
+ them correctly.
+ """
+ for r in required:
+ if r not in params:
+ raise PayPalError("Missing required param: %s" % r)
+
+ # Upper case all the parameters for PayPal.
+ return (dict((k.upper(), v) for k, v in params.iteritems()))
+
+ def _parse_response(self, response):
+ """Turn the PayPal response into a dict"""
+ response_tokens = {}
+ for kv in response.split('&'):
+ key, value = kv.split("=")
+ response_tokens[key.lower()] = urllib.unquote(value)
+ return response_tokens
\ No newline at end of file
diff --git a/paypal/pro/models.py b/paypal/pro/models.py
index 9359887..ff1e780 100644
--- a/paypal/pro/models.py
+++ b/paypal/pro/models.py
@@ -6,99 +6,99 @@
from django.forms.models import model_to_dict
from django.contrib.auth.models import User
try:
- from idmapper.models import SharedMemoryModel as Model
+ from idmapper.models import SharedMemoryModel as Model
except ImportError:
- Model = models.Model
+ Model = models.Model
class PayPalNVP(Model):
- """Record of a NVP interaction with PayPal."""
- TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # 2009-02-03T17:47:41Z
- RESTRICTED_FIELDS = L("expdate cvv2 acct")
- ADMIN_FIELDS = L("id user flag flag_code flag_info query response created_at updated_at ")
- ITEM_FIELDS = L("amt custom invnum")
- DIRECT_FIELDS = L("firstname lastname street city state countrycode zip")
+ """Record of a NVP interaction with PayPal."""
+ TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # 2009-02-03T17:47:41Z
+ RESTRICTED_FIELDS = L("expdate cvv2 acct")
+ ADMIN_FIELDS = L("id user flag flag_code flag_info query response created_at updated_at ")
+ ITEM_FIELDS = L("amt custom invnum")
+ DIRECT_FIELDS = L("firstname lastname street city state countrycode zip")
- # Response fields
- method = models.CharField(max_length=64, blank=True)
- ack = models.CharField(max_length=32, blank=True)
- profilestatus = models.CharField(max_length=32, blank=True)
- timestamp = models.DateTimeField(blank=True, null=True)
- profileid = models.CharField(max_length=32, blank=True) # I-E596DFUSD882
- profilereference = models.CharField(max_length=128, blank=True) # PROFILEREFERENCE
- correlationid = models.CharField(max_length=32, blank=True) # 25b380cda7a21
- token = models.CharField(max_length=64, blank=True)
- payerid = models.CharField(max_length=64, blank=True)
-
- # Transaction Fields
- firstname = models.CharField("First Name", max_length=255, blank=True)
- lastname = models.CharField("Last Name", max_length=255, blank=True)
- street = models.CharField("Street Address", max_length=255, blank=True)
- city = models.CharField("City", max_length=255, blank=True)
- state = models.CharField("State", max_length=255, blank=True)
- countrycode = models.CharField("Country", max_length=2,blank=True)
- zip = models.CharField("Postal / Zip Code", max_length=32, blank=True)
-
- # Custom fields
- invnum = models.CharField(max_length=255, blank=True)
- custom = models.CharField(max_length=255, blank=True)
-
- # Admin fields
- user = models.ForeignKey(User, blank=True, null=True)
- flag = models.BooleanField(default=False, blank=True)
- flag_code = models.CharField(max_length=32, blank=True)
- flag_info = models.TextField(blank=True)
- ipaddress = models.IPAddressField(blank=True)
- query = models.TextField(blank=True)
- response = models.TextField(blank=True)
- created_at = models.DateTimeField(auto_now_add=True)
- updated_at = models.DateTimeField(auto_now=True)
-
- class Meta:
- db_table = "paypal_nvp"
- verbose_name = "PayPal NVP"
-
- def init(self, request, paypal_request, paypal_response):
- """Initialize a PayPalNVP instance from a HttpRequest."""
- self.ipaddress = request.META.get('REMOTE_ADDR', '').split(':')[0]
- if hasattr(request, "user") and request.user.is_authenticated():
- self.user = request.user
+ # Response fields
+ method = models.CharField(max_length=64, blank=True)
+ ack = models.CharField(max_length=32, blank=True)
+ profilestatus = models.CharField(max_length=32, blank=True)
+ timestamp = models.DateTimeField(blank=True, null=True)
+ profileid = models.CharField(max_length=32, blank=True) # I-E596DFUSD882
+ profilereference = models.CharField(max_length=128, blank=True) # PROFILEREFERENCE
+ correlationid = models.CharField(max_length=32, blank=True) # 25b380cda7a21
+ token = models.CharField(max_length=64, blank=True)
+ payerid = models.CharField(max_length=64, blank=True)
+
+ # Transaction Fields
+ firstname = models.CharField("First Name", max_length=255, blank=True)
+ lastname = models.CharField("Last Name", max_length=255, blank=True)
+ street = models.CharField("Street Address", max_length=255, blank=True)
+ city = models.CharField("City", max_length=255, blank=True)
+ state = models.CharField("State", max_length=255, blank=True)
+ countrycode = models.CharField("Country", max_length=2,blank=True)
+ zip = models.CharField("Postal / Zip Code", max_length=32, blank=True)
+
+ # Custom fields
+ invnum = models.CharField(max_length=255, blank=True)
+ custom = models.CharField(max_length=255, blank=True)
+
+ # Admin fields
+ user = models.ForeignKey(User, blank=True, null=True)
+ flag = models.BooleanField(default=False, blank=True)
+ flag_code = models.CharField(max_length=32, blank=True)
+ flag_info = models.TextField(blank=True)
+ ipaddress = models.IPAddressField(blank=True)
+ query = models.TextField(blank=True)
+ response = models.TextField(blank=True)
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
+
+ class Meta:
+ db_table = "paypal_nvp"
+ verbose_name = "PayPal NVP"
+
+ def init(self, request, paypal_request, paypal_response):
+ """Initialize a PayPalNVP instance from a HttpRequest."""
+ self.ipaddress = request.META.get('REMOTE_ADDR', '').split(':')[0]
+ if hasattr(request, "user") and request.user.is_authenticated():
+ self.user = request.user
- # No storing credit card info.
- query_data = dict((k,v) for k, v in paypal_request.iteritems() if k not in self.RESTRICTED_FIELDS)
- self.query = urlencode(query_data)
- self.response = urlencode(paypal_response)
+ # No storing credit card info.
+ query_data = dict((k,v) for k, v in paypal_request.iteritems() if k not in self.RESTRICTED_FIELDS)
+ self.query = urlencode(query_data)
+ self.response = urlencode(paypal_response)
- # Was there a flag on the play?
- ack = paypal_response.get('ack', False)
- if ack != "Success":
- if ack == "SuccessWithWarning":
- self.flag_info = paypal_response.get('l_longmessage0', '')
- else:
- self.set_flag(paypal_response.get('l_longmessage0', ''), paypal_response.get('l_errorcode', ''))
+ # Was there a flag on the play?
+ ack = paypal_response.get('ack', False)
+ if ack != "Success":
+ if ack == "SuccessWithWarning":
+ self.flag_info = paypal_response.get('l_longmessage0', '')
+ else:
+ self.set_flag(paypal_response.get('l_longmessage0', ''), paypal_response.get('l_errorcode', ''))
- def set_flag(self, info, code=None):
- """Flag this instance for investigation."""
- self.flag = True
- self.flag_info += info
- if code is not None:
- self.flag_code = code
+ def set_flag(self, info, code=None):
+ """Flag this instance for investigation."""
+ self.flag = True
+ self.flag_info += info
+ if code is not None:
+ self.flag_code = code
- def process(self, request, item):
- """Do a direct payment."""
- from paypal.pro.helpers import PayPalWPP
- wpp = PayPalWPP(request)
+ def process(self, request, item):
+ """Do a direct payment."""
+ from paypal.pro.helpers import PayPalWPP
+ wpp = PayPalWPP(request)
- # Change the model information into a dict that PayPal can understand.
- params = model_to_dict(self, exclude=self.ADMIN_FIELDS)
- params['acct'] = self.acct
- params['creditcardtype'] = self.creditcardtype
- params['expdate'] = self.expdate
- params['cvv2'] = self.cvv2
- params.update(item)
+ # Change the model information into a dict that PayPal can understand.
+ params = model_to_dict(self, exclude=self.ADMIN_FIELDS)
+ params['acct'] = self.acct
+ params['creditcardtype'] = self.creditcardtype
+ params['expdate'] = self.expdate
+ params['cvv2'] = self.cvv2
+ params.update(item)
- # Create recurring payment:
- if 'billingperiod' in params:
- return wpp.createRecurringPaymentsProfile(params, direct=True)
- # Create single payment:
- else:
- return wpp.doDirectPayment(params)
+ # Create recurring payment:
+ if 'billingperiod' in params:
+ return wpp.createRecurringPaymentsProfile(params, direct=True)
+ # Create single payment:
+ else:
+ return wpp.doDirectPayment(params)
diff --git a/paypal/pro/tests.py b/paypal/pro/tests.py
index cbf360f..4af3357 100644
--- a/paypal/pro/tests.py
+++ b/paypal/pro/tests.py
@@ -12,111 +12,111 @@
from paypal.pro.exceptions import PayPalFailure
class RequestFactory(Client):
- # Used to generate request objects.
- def request(self, **request):
- environ = {
- 'HTTP_COOKIE': self.cookies,
- 'PATH_INFO': '/',
- 'QUERY_STRING': '',
- 'REQUEST_METHOD': 'GET',
- 'SCRIPT_NAME': '',
- 'SERVER_NAME': 'testserver',
- 'SERVER_PORT': 80,
- 'SERVER_PROTOCOL': 'HTTP/1.1',
- }
- environ.update(self.defaults)
- environ.update(request)
- return WSGIRequest(environ)
+ # Used to generate request objects.
+ def request(self, **request):
+ environ = {
+ 'HTTP_COOKIE': self.cookies,
+ 'PATH_INFO': '/',
+ 'QUERY_STRING': '',
+ 'REQUEST_METHOD': 'GET',
+ 'SCRIPT_NAME': '',
+ 'SERVER_NAME': 'testserver',
+ 'SERVER_PORT': 80,
+ 'SERVER_PROTOCOL': 'HTTP/1.1',
+ }
+ environ.update(self.defaults)
+ environ.update(request)
+ return WSGIRequest(environ)
RF = RequestFactory()
REQUEST = RF.get("/pay/", REMOTE_ADDR="127.0.0.1:8000")
class DummyPayPalWPP(PayPalWPP):
- pass
-# """Dummy class for testing PayPalWPP."""
-# responses = {
-# # @@@ Need some reals data here.
-# "DoDirectPayment": """ack=Success×tamp=2009-03-12T23%3A52%3A33Z&l_severitycode0=Error&l_shortmessage0=Security+error&l_longmessage0=Security+header+is+not+valid&version=54.0&build=854529&l_errorcode0=&correlationid=""",
-# }
+ pass
+# """Dummy class for testing PayPalWPP."""
+# responses = {
+# # @@@ Need some reals data here.
+# "DoDirectPayment": """ack=Success×tamp=2009-03-12T23%3A52%3A33Z&l_severitycode0=Error&l_shortmessage0=Security+error&l_longmessage0=Security+header+is+not+valid&version=54.0&build=854529&l_errorcode0=&correlationid=""",
+# }
#
-# def _request(self, data):
-# return self.responses["DoDirectPayment"]
+# def _request(self, data):
+# return self.responses["DoDirectPayment"]
class CreditCardFieldTest(TestCase):
- def test_CreditCardField(self):
- field = CreditCardField()
- field.clean('4797503429879309')
- self.assertEquals(field.card_type, "Visa")
- self.assertRaises(ValidationError, CreditCardField().clean, '1234567890123455')
+ def test_CreditCardField(self):
+ field = CreditCardField()
+ field.clean('4797503429879309')
+ self.assertEquals(field.card_type, "Visa")
+ self.assertRaises(ValidationError, CreditCardField().clean, '1234567890123455')
- def test_invalidCreditCards(self):
- self.assertEquals(CreditCardField().clean('4797-5034-2987-9309'), '4797503429879309')
-
+ def test_invalidCreditCards(self):
+ self.assertEquals(CreditCardField().clean('4797-5034-2987-9309'), '4797503429879309')
+
class PayPalWPPTest(TestCase):
- def setUp(self):
-
- # Avoding blasting real requests at PayPal.
- self.old_debug = settings.DEBUG
- settings.DEBUG = True
-
- self.item = {
- 'amt': '9.95',
- 'inv': 'inv',
- 'custom': 'custom',
- 'next': 'http://www.example.com/next/',
- 'returnurl': 'http://www.example.com/pay/',
- 'cancelurl': 'http://www.example.com/cancel/'
- }
- self.wpp = DummyPayPalWPP(REQUEST)
-
- def tearDown(self):
- settings.DEBUG = self.old_debug
+ def setUp(self):
+
+ # Avoding blasting real requests at PayPal.
+ self.old_debug = settings.DEBUG
+ settings.DEBUG = True
+
+ self.item = {
+ 'amt': '9.95',
+ 'inv': 'inv',
+ 'custom': 'custom',
+ 'next': 'http://www.example.com/next/',
+ 'returnurl': 'http://www.example.com/pay/',
+ 'cancelurl': 'http://www.example.com/cancel/'
+ }
+ self.wpp = DummyPayPalWPP(REQUEST)
+
+ def tearDown(self):
+ settings.DEBUG = self.old_debug
- def test_doDirectPayment_missing_params(self):
- data = {'firstname': 'Chewbacca'}
- self.assertRaises(PayPalError, self.wpp.doDirectPayment, data)
+ def test_doDirectPayment_missing_params(self):
+ data = {'firstname': 'Chewbacca'}
+ self.assertRaises(PayPalError, self.wpp.doDirectPayment, data)
- def test_doDirectPayment_valid(self):
- data = {
- 'firstname': 'Brave',
- 'lastname': 'Star',
- 'street': '1 Main St',
- 'city': u'San Jos\xe9',
- 'state': 'CA',
- 'countrycode': 'US',
- 'zip': '95131',
- 'expdate': '012019',
- 'cvv2': '037',
- 'acct': '4797503429879309',
- 'creditcardtype': 'visa',
- 'ipaddress': '10.0.1.199',}
- data.update(self.item)
- self.assertTrue(self.wpp.doDirectPayment(data))
-
- def test_doDirectPayment_invalid(self):
- data = {
- 'firstname': 'Epic',
- 'lastname': 'Fail',
- 'street': '100 Georgia St',
- 'city': 'Vancouver',
- 'state': 'BC',
- 'countrycode': 'CA',
- 'zip': 'V6V 1V1',
- 'expdate': '012019',
- 'cvv2': '999',
- 'acct': '1234567890',
- 'creditcardtype': 'visa',
- 'ipaddress': '10.0.1.199',}
- data.update(self.item)
- self.assertRaises(PayPalFailure, self.wpp.doDirectPayment, data)
+ def test_doDirectPayment_valid(self):
+ data = {
+ 'firstname': 'Brave',
+ 'lastname': 'Star',
+ 'street': '1 Main St',
+ 'city': u'San Jos\xe9',
+ 'state': 'CA',
+ 'countrycode': 'US',
+ 'zip': '95131',
+ 'expdate': '012019',
+ 'cvv2': '037',
+ 'acct': '4797503429879309',
+ 'creditcardtype': 'visa',
+ 'ipaddress': '10.0.1.199',}
+ data.update(self.item)
+ self.assertTrue(self.wpp.doDirectPayment(data))
+
+ def test_doDirectPayment_invalid(self):
+ data = {
+ 'firstname': 'Epic',
+ 'lastname': 'Fail',
+ 'street': '100 Georgia St',
+ 'city': 'Vancouver',
+ 'state': 'BC',
+ 'countrycode': 'CA',
+ 'zip': 'V6V 1V1',
+ 'expdate': '012019',
+ 'cvv2': '999',
+ 'acct': '1234567890',
+ 'creditcardtype': 'visa',
+ 'ipaddress': '10.0.1.199',}
+ data.update(self.item)
+ self.assertRaises(PayPalFailure, self.wpp.doDirectPayment, data)
- def test_setExpressCheckout(self):
- # We'll have to stub out tests for doExpressCheckoutPayment and friends
- # because they're behind paypal's doors.
- nvp_obj = self.wpp.setExpressCheckout(self.item)
- self.assertTrue(nvp_obj.ack == "Success")
+ def test_setExpressCheckout(self):
+ # We'll have to stub out tests for doExpressCheckoutPayment and friends
+ # because they're behind paypal's doors.
+ nvp_obj = self.wpp.setExpressCheckout(self.item)
+ self.assertTrue(nvp_obj.ack == "Success")
### DoExpressCheckoutPayment
diff --git a/paypal/pro/views.py b/paypal/pro/views.py
index e28978f..a898325 100644
--- a/paypal/pro/views.py
+++ b/paypal/pro/views.py
@@ -17,185 +17,185 @@
class PayPalPro(object):
- """
- This class-based view takes care of PayPal WebsitePaymentsPro (WPP).
- PayPalPro has two separate flows - DirectPayment and ExpressPayFlow. In
- DirectPayment the user buys on your site. In ExpressPayFlow the user is
- direct to PayPal to confirm their purchase. PayPalPro implements both
- flows. To it create an instance using the these parameters:
-
- item: a dictionary that holds information about the item being purchased.
-
- For single item purchase (pay once):
-
- Required Keys:
- * amt: Float amount of the item.
-
- Optional Keys:
- * custom: You can set this to help you identify a transaction.
- * invnum: Unique ID that identifies this transaction.
-
- For recurring billing:
-
- Required Keys:
- * amt: Float amount for each billing cycle.
- * billingperiod: String unit of measure for the billing cycle (Day|Week|SemiMonth|Month|Year)
- * billingfrequency: Integer number of periods that make up a cycle.
- * profilestartdate: The date to begin billing. "2008-08-05T17:00:00Z" UTC/GMT
- * desc: Description of what you're billing for.
-
- Optional Keys:
- * trialbillingperiod: String unit of measure for trial cycle (Day|Week|SemiMonth|Month|Year)
- * trialbillingfrequency: Integer # of periods in a cycle.
- * trialamt: Float amount to bill for the trial period.
- * trialtotalbillingcycles: Integer # of cycles for the trial payment period.
- * failedinitamtaction: set to continue on failure (ContinueOnFailure / CancelOnFailure)
- * maxfailedpayments: number of payments before profile is suspended.
- * autobilloutamt: automatically bill outstanding amount.
- * subscribername: Full name of the person who paid.
- * profilereference: Unique reference or invoice number.
- * taxamt: How much tax.
- * initamt: Initial non-recurring payment due upon creation.
- * currencycode: defaults to USD
- * + a bunch of shipping fields
-
- payment_form_cls: form class that will be used to display the payment form.
- It should inherit from `paypal.pro.forms.PaymentForm` if you're adding more.
-
- payment_template: template used to ask the dude for monies. To comply with
- PayPal standards it must include a link to PayPal Express Checkout.
-
- confirm_form_cls: form class that will be used to display the confirmation form.
- It should inherit from `paypal.pro.forms.ConfirmForm`. It is only used in the Express flow.
-
- success_url / fail_url: URLs to be redirected to when the payment successful or fails.
- """
- errors = {
- "processing": "There was an error processing your payment. Check your information and try again.",
- "form": "Please correct the errors below and try again.",
- "paypal": "There was a problem contacting PayPal. Please try again later."
- }
-
- def __init__(self, item=None, payment_form_cls=PaymentForm,
- payment_template="pro/payment.html", confirm_form_cls=ConfirmForm,
- confirm_template="pro/confirm.html", success_url="?success",
- fail_url=None, context=None, form_context_name="form"):
- self.item = item
- self.payment_form_cls = payment_form_cls
- self.payment_template = payment_template
- self.confirm_form_cls = confirm_form_cls
- self.confirm_template = confirm_template
- self.success_url = success_url
- self.fail_url = fail_url
- self.context = context or {}
- self.form_context_name = form_context_name
-
- def __call__(self, request):
- """Return the appropriate response for the state of the transaction."""
- self.request = request
- if request.method == "GET":
- if self.should_redirect_to_express():
- return self.redirect_to_express()
- elif self.should_render_confirm_form():
- return self.render_confirm_form()
- elif self.should_render_payment_form():
- return self.render_payment_form()
- else:
- if self.should_validate_confirm_form():
- return self.validate_confirm_form()
- elif self.should_validate_payment_form():
- return self.validate_payment_form()
-
- # Default to the rendering the payment form.
- return self.render_payment_form()
-
- def is_recurring(self):
- return self.item is not None and 'billingperiod' in self.item
-
- def should_redirect_to_express(self):
- return 'express' in self.request.GET
-
- def should_render_confirm_form(self):
- return 'token' in self.request.GET and 'PayerID' in self.request.GET
-
- def should_render_payment_form(self):
- return True
-
- def should_validate_confirm_form(self):
- return 'token' in self.request.POST and 'PayerID' in self.request.POST
-
- def should_validate_payment_form(self):
- return True
-
- def render_payment_form(self):
- """Display the DirectPayment for entering payment information."""
- self.context[self.form_context_name] = self.payment_form_cls()
- return render_to_response(self.payment_template, self.context, RequestContext(self.request))
-
- def validate_payment_form(self):
- """Try to validate and then process the DirectPayment form."""
- form = self.payment_form_cls(self.request.POST)
- if form.is_valid():
- success = form.process(self.request, self.item)
- if success:
- return HttpResponseRedirect(self.success_url)
- else:
- self.context['errors'] = self.errors['processing']
-
- self.context[self.form_context_name] = form
- self.context.setdefault("errors", self.errors['form'])
- return render_to_response(self.payment_template, self.context, RequestContext(self.request))
-
- def get_endpoint(self):
- if TEST:
- return SANDBOX_EXPRESS_ENDPOINT
- else:
- return EXPRESS_ENDPOINT
-
- def redirect_to_express(self):
- """
- First step of ExpressCheckout. Redirect the request to PayPal using the
- data returned from setExpressCheckout.
- """
- wpp = PayPalWPP(self.request)
- try:
- nvp_obj = wpp.setExpressCheckout(self.item)
- except PayPalFailure:
- self.context['errors'] = self.errors['paypal']
- return self.render_payment_form()
- else:
- pp_params = dict(token=nvp_obj.token, AMT=self.item['amt'],
- RETURNURL=self.item['returnurl'],
- CANCELURL=self.item['cancelurl'])
- pp_url = self.get_endpoint() % urlencode(pp_params)
- return HttpResponseRedirect(pp_url)
-
- def render_confirm_form(self):
- """
- Second step of ExpressCheckout. Display an order confirmation form which
- contains hidden fields with the token / PayerID from PayPal.
- """
- initial = dict(token=self.request.GET['token'], PayerID=self.request.GET['PayerID'])
- self.context[self.form_context_name] = self.confirm_form_cls(initial=initial)
- return render_to_response(self.confirm_template, self.context, RequestContext(self.request))
-
- def validate_confirm_form(self):
- """
- Third and final step of ExpressCheckout. Request has pressed the confirmation but
- and we can send the final confirmation to PayPal using the data from the POST'ed form.
- """
- wpp = PayPalWPP(self.request)
- pp_data = dict(token=self.request.POST['token'], payerid=self.request.POST['PayerID'])
- self.item.update(pp_data)
-
- # @@@ This check and call could be moved into PayPalWPP.
- try:
- if self.is_recurring():
- nvp_obj = wpp.createRecurringPaymentsProfile(self.item)
- else:
- nvp_obj = wpp.doExpressCheckoutPayment(self.item)
- except PayPalFailure:
- self.context['errors'] = self.errors['processing']
- return self.render_payment_form()
- else:
- return HttpResponseRedirect(self.success_url)
+ """
+ This class-based view takes care of PayPal WebsitePaymentsPro (WPP).
+ PayPalPro has two separate flows - DirectPayment and ExpressPayFlow. In
+ DirectPayment the user buys on your site. In ExpressPayFlow the user is
+ direct to PayPal to confirm their purchase. PayPalPro implements both
+ flows. To it create an instance using the these parameters:
+
+ item: a dictionary that holds information about the item being purchased.
+
+ For single item purchase (pay once):
+
+ Required Keys:
+ * amt: Float amount of the item.
+
+ Optional Keys:
+ * custom: You can set this to help you identify a transaction.
+ * invnum: Unique ID that identifies this transaction.
+
+ For recurring billing:
+
+ Required Keys:
+ * amt: Float amount for each billing cycle.
+ * billingperiod: String unit of measure for the billing cycle (Day|Week|SemiMonth|Month|Year)
+ * billingfrequency: Integer number of periods that make up a cycle.
+ * profilestartdate: The date to begin billing. "2008-08-05T17:00:00Z" UTC/GMT
+ * desc: Description of what you're billing for.
+
+ Optional Keys:
+ * trialbillingperiod: String unit of measure for trial cycle (Day|Week|SemiMonth|Month|Year)
+ * trialbillingfrequency: Integer # of periods in a cycle.
+ * trialamt: Float amount to bill for the trial period.
+ * trialtotalbillingcycles: Integer # of cycles for the trial payment period.
+ * failedinitamtaction: set to continue on failure (ContinueOnFailure / CancelOnFailure)
+ * maxfailedpayments: number of payments before profile is suspended.
+ * autobilloutamt: automatically bill outstanding amount.
+ * subscribername: Full name of the person who paid.
+ * profilereference: Unique reference or invoice number.
+ * taxamt: How much tax.
+ * initamt: Initial non-recurring payment due upon creation.
+ * currencycode: defaults to USD
+ * + a bunch of shipping fields
+
+ payment_form_cls: form class that will be used to display the payment form.
+ It should inherit from `paypal.pro.forms.PaymentForm` if you're adding more.
+
+ payment_template: template used to ask the dude for monies. To comply with
+ PayPal standards it must include a link to PayPal Express Checkout.
+
+ confirm_form_cls: form class that will be used to display the confirmation form.
+ It should inherit from `paypal.pro.forms.ConfirmForm`. It is only used in the Express flow.
+
+ success_url / fail_url: URLs to be redirected to when the payment successful or fails.
+ """
+ errors = {
+ "processing": "There was an error processing your payment. Check your information and try again.",
+ "form": "Please correct the errors below and try again.",
+ "paypal": "There was a problem contacting PayPal. Please try again later."
+ }
+
+ def __init__(self, item=None, payment_form_cls=PaymentForm,
+ payment_template="pro/payment.html", confirm_form_cls=ConfirmForm,
+ confirm_template="pro/confirm.html", success_url="?success",
+ fail_url=None, context=None, form_context_name="form"):
+ self.item = item
+ self.payment_form_cls = payment_form_cls
+ self.payment_template = payment_template
+ self.confirm_form_cls = confirm_form_cls
+ self.confirm_template = confirm_template
+ self.success_url = success_url
+ self.fail_url = fail_url
+ self.context = context or {}
+ self.form_context_name = form_context_name
+
+ def __call__(self, request):
+ """Return the appropriate response for the state of the transaction."""
+ self.request = request
+ if request.method == "GET":
+ if self.should_redirect_to_express():
+ return self.redirect_to_express()
+ elif self.should_render_confirm_form():
+ return self.render_confirm_form()
+ elif self.should_render_payment_form():
+ return self.render_payment_form()
+ else:
+ if self.should_validate_confirm_form():
+ return self.validate_confirm_form()
+ elif self.should_validate_payment_form():
+ return self.validate_payment_form()
+
+ # Default to the rendering the payment form.
+ return self.render_payment_form()
+
+ def is_recurring(self):
+ return self.item is not None and 'billingperiod' in self.item
+
+ def should_redirect_to_express(self):
+ return 'express' in self.request.GET
+
+ def should_render_confirm_form(self):
+ return 'token' in self.request.GET and 'PayerID' in self.request.GET
+
+ def should_render_payment_form(self):
+ return True
+
+ def should_validate_confirm_form(self):
+ return 'token' in self.request.POST and 'PayerID' in self.request.POST
+
+ def should_validate_payment_form(self):
+ return True
+
+ def render_payment_form(self):
+ """Display the DirectPayment for entering payment information."""
+ self.context[self.form_context_name] = self.payment_form_cls()
+ return render_to_response(self.payment_template, self.context, RequestContext(self.request))
+
+ def validate_payment_form(self):
+ """Try to validate and then process the DirectPayment form."""
+ form = self.payment_form_cls(self.request.POST)
+ if form.is_valid():
+ success = form.process(self.request, self.item)
+ if success:
+ return HttpResponseRedirect(self.success_url)
+ else:
+ self.context['errors'] = self.errors['processing']
+
+ self.context[self.form_context_name] = form
+ self.context.setdefault("errors", self.errors['form'])
+ return render_to_response(self.payment_template, self.context, RequestContext(self.request))
+
+ def get_endpoint(self):
+ if TEST:
+ return SANDBOX_EXPRESS_ENDPOINT
+ else:
+ return EXPRESS_ENDPOINT
+
+ def redirect_to_express(self):
+ """
+ First step of ExpressCheckout. Redirect the request to PayPal using the
+ data returned from setExpressCheckout.
+ """
+ wpp = PayPalWPP(self.request)
+ try:
+ nvp_obj = wpp.setExpressCheckout(self.item)
+ except PayPalFailure:
+ self.context['errors'] = self.errors['paypal']
+ return self.render_payment_form()
+ else:
+ pp_params = dict(token=nvp_obj.token, AMT=self.item['amt'],
+ RETURNURL=self.item['returnurl'],
+ CANCELURL=self.item['cancelurl'])
+ pp_url = self.get_endpoint() % urlencode(pp_params)
+ return HttpResponseRedirect(pp_url)
+
+ def render_confirm_form(self):
+ """
+ Second step of ExpressCheckout. Display an order confirmation form which
+ contains hidden fields with the token / PayerID from PayPal.
+ """
+ initial = dict(token=self.request.GET['token'], PayerID=self.request.GET['PayerID'])
+ self.context[self.form_context_name] = self.confirm_form_cls(initial=initial)
+ return render_to_response(self.confirm_template, self.context, RequestContext(self.request))
+
+ def validate_confirm_form(self):
+ """
+ Third and final step of ExpressCheckout. Request has pressed the confirmation but
+ and we can send the final confirmation to PayPal using the data from the POST'ed form.
+ """
+ wpp = PayPalWPP(self.request)
+ pp_data = dict(token=self.request.POST['token'], payerid=self.request.POST['PayerID'])
+ self.item.update(pp_data)
+
+ # @@@ This check and call could be moved into PayPalWPP.
+ try:
+ if self.is_recurring():
+ nvp_obj = wpp.createRecurringPaymentsProfile(self.item)
+ else:
+ nvp_obj = wpp.doExpressCheckoutPayment(self.item)
+ except PayPalFailure:
+ self.context['errors'] = self.errors['processing']
+ return self.render_payment_form()
+ else:
+ return HttpResponseRedirect(self.success_url)
diff --git a/paypal/standard/conf.py b/paypal/standard/conf.py
index 5c5fd45..7d54e87 100644
--- a/paypal/standard/conf.py
+++ b/paypal/standard/conf.py
@@ -1,8 +1,8 @@
from django.conf import settings
class PayPalSettingsError(Exception):
- """Raised when settings be bad."""
-
+ """Raised when settings be bad."""
+
TEST = getattr(settings, "PAYPAL_TEST", True)
diff --git a/paypal/standard/forms.py b/paypal/standard/forms.py
index e9992a5..a45b02f 100644
--- a/paypal/standard/forms.py
+++ b/paypal/standard/forms.py
@@ -5,215 +5,249 @@
from django.utils.safestring import mark_safe
from paypal.standard.conf import *
from paypal.standard.widgets import ValueHiddenInput, ReservedValueHiddenInput
-from paypal.standard.conf import (POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT,
- RECEIVER_EMAIL)
-
+from paypal.standard.conf import (POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT,
+ RECEIVER_EMAIL)
+import urllib
+import uuid
# 20:18:05 Jan 30, 2009 PST - PST timezone support is not included out of the box.
# PAYPAL_DATE_FORMAT = ("%H:%M:%S %b. %d, %Y PST", "%H:%M:%S %b %d, %Y PST",)
# PayPal dates have been spotted in the wild with these formats, beware!
PAYPAL_DATE_FORMAT = ("%H:%M:%S %b. %d, %Y PST",
- "%H:%M:%S %b. %d, %Y PDT",
- "%H:%M:%S %b %d, %Y PST",
- "%H:%M:%S %b %d, %Y PDT",)
+ "%H:%M:%S %b. %d, %Y PDT",
+ "%H:%M:%S %b %d, %Y PST",
+ "%H:%M:%S %b %d, %Y PDT",)
class PayPalPaymentsForm(forms.Form):
- """
- Creates a PayPal Payments Standard "Buy It Now" button, configured for a
- selling a single item with no shipping.
-
- For a full overview of all the fields you can set (there is a lot!) see:
- http://tinyurl.com/pps-integration
-
- Usage:
- >>> f = PayPalPaymentsForm(initial={'item_name':'Widget 001', ...})
- >>> f.render()
- u'""" % (POSTBACK_ENDPOINT, self.as_p(), self.get_image()))
-
-
- def sandbox(self):
- return mark_safe(u"""""" % (SANDBOX_POSTBACK_ENDPOINT, self.as_p(), self.get_image()))
-
- def get_image(self):
- return {
- (True, self.SUBSCRIBE): SUBSCRIPTION_SANDBOX_IMAGE,
- (True, self.BUY): SANDBOX_IMAGE,
- (True, self.DONATE): DONATION_SANDBOX_IMAGE,
- (False, self.SUBSCRIBE): SUBSCRIPTION_IMAGE,
- (False, self.BUY): IMAGE,
- (False, self.DONATE): DONATION_IMAGE,
- }[TEST, self.button_type]
- def is_transaction(self):
- return not self.is_subscription()
+ def get_image(self):
+ return {
+ (True, self.SUBSCRIBE): SUBSCRIPTION_SANDBOX_IMAGE,
+ (True, self.BUY): SANDBOX_IMAGE,
+ (True, self.DONATE): DONATION_SANDBOX_IMAGE,
+ (False, self.SUBSCRIBE): SUBSCRIPTION_IMAGE,
+ (False, self.BUY): IMAGE,
+ (False, self.DONATE): DONATION_IMAGE,
+ }[TEST, self.button_type]
+
+ def is_transaction(self):
+ return not self.is_subscription()
- def is_donation(self):
- return self.button_type == self.DONATE
+ def is_donation(self):
+ return self.button_type == self.DONATE
- def is_subscription(self):
- return self.button_type == self.SUBSCRIBE
+ def is_subscription(self):
+ return self.button_type == self.SUBSCRIBE
class PayPalEncryptedPaymentsForm(PayPalPaymentsForm):
- """
- Creates a PayPal Encrypted Payments "Buy It Now" button.
- Requires the M2Crypto package.
-
- Based on example at:
- http://blog.mauveweb.co.uk/2007/10/10/paypal-with-django/
-
- """
- def _encrypt(self):
- """Use your key thing to encrypt things."""
- from M2Crypto import BIO, SMIME, X509
- # @@@ Could we move this to conf.py?
- CERT = settings.PAYPAL_PRIVATE_CERT
- PUB_CERT = settings.PAYPAL_PUBLIC_CERT
- PAYPAL_CERT = settings.PAYPAL_CERT
- CERT_ID = settings.PAYPAL_CERT_ID
-
- # Iterate through the fields and pull out the ones that have a value.
- plaintext = 'cert_id=%s\n' % CERT_ID
- for name, field in self.fields.iteritems():
- value = None
- if name in self.initial:
- value = self.initial[name]
- elif field.initial is not None:
- value = field.initial
- if value is not None:
- # @@@ Make this less hackish and put it in the widget.
- if name == "return_url":
- name = "return"
- plaintext += u'%s=%s\n' % (name, value)
- plaintext = plaintext.encode('utf-8')
-
- # Begin crypto weirdness.
- s = SMIME.SMIME()
- s.load_key_bio(BIO.openfile(CERT), BIO.openfile(PUB_CERT))
- p7 = s.sign(BIO.MemoryBuffer(plaintext), flags=SMIME.PKCS7_BINARY)
- x509 = X509.load_cert_bio(BIO.openfile(settings.PAYPAL_CERT))
- sk = X509.X509_Stack()
- sk.push(x509)
- s.set_x509_stack(sk)
- s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
- tmp = BIO.MemoryBuffer()
- p7.write_der(tmp)
- p7 = s.encrypt(tmp, flags=SMIME.PKCS7_BINARY)
- out = BIO.MemoryBuffer()
- p7.write(out)
- return out.read()
-
- def as_p(self):
- return mark_safe(u"""
+ """
+ Creates a PayPal Encrypted Payments "Buy It Now" button.
+ Requires the M2Crypto package.
+
+ Based on example at:
+ http://blog.mauveweb.co.uk/2007/10/10/paypal-with-django/
+
+ """
+ def _encrypt(self):
+ """Use your key thing to encrypt things."""
+ from M2Crypto import BIO, SMIME, X509
+ # @@@ Could we move this to conf.py?
+ CERT = settings.PAYPAL_PRIVATE_CERT
+ PUB_CERT = settings.PAYPAL_PUBLIC_CERT
+ PAYPAL_CERT = settings.PAYPAL_CERT
+ CERT_ID = settings.PAYPAL_CERT_ID
+
+ # Iterate through the fields and pull out the ones that have a value.
+ plaintext = 'cert_id=%s\n' % CERT_ID
+ for name, field in self.fields.iteritems():
+ value = None
+ if name in self.initial:
+ value = self.initial[name]
+ elif field.initial is not None:
+ value = field.initial
+ if value is not None:
+ # @@@ Make this less hackish and put it in the widget.
+ if name == "return_url":
+ name = "return"
+ plaintext += u'%s=%s\n' % (name, value)
+ plaintext = plaintext.encode('utf-8')
+
+ # Begin crypto weirdness.
+ s = SMIME.SMIME()
+ s.load_key_bio(BIO.openfile(CERT), BIO.openfile(PUB_CERT))
+ p7 = s.sign(BIO.MemoryBuffer(plaintext), flags=SMIME.PKCS7_BINARY)
+ x509 = X509.load_cert_bio(BIO.openfile(settings.PAYPAL_CERT))
+ sk = X509.X509_Stack()
+ sk.push(x509)
+ s.set_x509_stack(sk)
+ s.set_cipher(SMIME.Cipher('des_ede3_cbc'))
+ tmp = BIO.MemoryBuffer()
+ p7.write_der(tmp)
+ p7 = s.encrypt(tmp, flags=SMIME.PKCS7_BINARY)
+ out = BIO.MemoryBuffer()
+ p7.write(out)
+ return out.read()
+
+ def as_p(self):
+ return mark_safe(u"""
- """ % self._encrypt())
+ """ % self._encrypt())
class PayPalSharedSecretEncryptedPaymentsForm(PayPalEncryptedPaymentsForm):
- """
- Creates a PayPal Encrypted Payments "Buy It Now" button with a Shared Secret.
- Shared secrets should only be used when your IPN endpoint is on HTTPS.
-
- Adds a secret to the notify_url based on the contents of the form.
-
- """
- def __init__(self, *args, **kwargs):
- "Make the secret from the form initial data and slip it into the form."
- from paypal.standard.helpers import make_secret
- super(PayPalSharedSecretEncryptedPaymentsForm, self).__init__(*args, **kwargs)
- # @@@ Attach the secret parameter in a way that is safe for other query params.
- secret_param = "?secret=%s" % make_secret(self)
- # Initial data used in form construction overrides defaults
- if 'notify_url' in self.initial:
- self.initial['notify_url'] += secret_param
- else:
- self.fields['notify_url'].initial += secret_param
+ """
+ Creates a PayPal Encrypted Payments "Buy It Now" button with a Shared Secret.
+ Shared secrets should only be used when your IPN endpoint is on HTTPS.
+
+ Adds a secret to the notify_url based on the contents of the form.
+
+ """
+ def __init__(self, *args, **kwargs):
+ "Make the secret from the form initial data and slip it into the form."
+ from paypal.standard.helpers import make_secret
+ super(PayPalSharedSecretEncryptedPaymentsForm, self).__init__(*args, **kwargs)
+ # @@@ Attach the secret parameter in a way that is safe for other query params.
+ secret_param = "?secret=%s" % make_secret(self)
+ # Initial data used in form construction overrides defaults
+ if 'notify_url' in self.initial:
+ self.initial['notify_url'] += secret_param
+ else:
+ self.fields['notify_url'].initial += secret_param
class PayPalStandardBaseForm(forms.ModelForm):
- """Form used to receive and record PayPal IPN/PDT."""
- # PayPal dates have non-standard formats.
- time_created = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
- payment_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
- 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)
+ """Form used to receive and record PayPal IPN/PDT."""
+ # PayPal dates have non-standard formats.
+ time_created = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
+ payment_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT)
+ 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)
diff --git a/paypal/standard/helpers.py b/paypal/standard/helpers.py
index f7bb269..2edbec7 100644
--- a/paypal/standard/helpers.py
+++ b/paypal/standard/helpers.py
@@ -3,57 +3,57 @@
from django.conf import settings
def duplicate_txn_id(ipn_obj):
- """Returns True if a record with this transaction id exists and it is not
- a payment which has gone from pending to completed.
-
- """
- query = ipn_obj._default_manager.filter(txn_id = ipn_obj.txn_id)
-
- if ipn_obj.payment_status == "Completed":
- # A payment that was pending and is now completed will have the same
- # IPN transaction id, so don't flag them as duplicates because it
- # means that the payment was finally successful!
- query = query.exclude(payment_status = "Pending")
-
- return query.count() > 0
-
+ """Returns True if a record with this transaction id exists and it is not
+ a payment which has gone from pending to completed.
+
+ """
+ query = ipn_obj._default_manager.filter(txn_id = ipn_obj.txn_id)
+
+ if ipn_obj.payment_status == "Completed":
+ # A payment that was pending and is now completed will have the same
+ # IPN transaction id, so don't flag them as duplicates because it
+ # means that the payment was finally successful!
+ query = query.exclude(payment_status = "Pending")
+
+ return query.count() > 0
+
def make_secret(form_instance, secret_fields=None):
- """
- Returns a secret for use in a EWP form or an IPN verification based on a
- selection of variables in params. Should only be used with SSL.
-
- """
- # @@@ Moved here as temporary fix to avoid dependancy on auth.models.
- from django.contrib.auth.models import get_hexdigest
- # @@@ amount is mc_gross on the IPN - where should mapping logic go?
- # @@@ amount / mc_gross is not nessecarily returned as it was sent - how to use it? 10.00 vs. 10.0
- # @@@ the secret should be based on the invoice or custom fields as well - otherwise its always the same.
-
- # Build the secret with fields availible in both PaymentForm and the IPN. Order matters.
- if secret_fields is None:
- secret_fields = ['business', 'item_name']
+ """
+ Returns a secret for use in a EWP form or an IPN verification based on a
+ selection of variables in params. Should only be used with SSL.
+
+ """
+ # @@@ Moved here as temporary fix to avoid dependancy on auth.models.
+ from django.contrib.auth.models import get_hexdigest
+ # @@@ amount is mc_gross on the IPN - where should mapping logic go?
+ # @@@ amount / mc_gross is not nessecarily returned as it was sent - how to use it? 10.00 vs. 10.0
+ # @@@ the secret should be based on the invoice or custom fields as well - otherwise its always the same.
+
+ # Build the secret with fields availible in both PaymentForm and the IPN. Order matters.
+ if secret_fields is None:
+ secret_fields = ['business', 'item_name']
- data = ""
- for name in secret_fields:
- if hasattr(form_instance, 'cleaned_data'):
- if name in form_instance.cleaned_data:
- data += unicode(form_instance.cleaned_data[name])
- else:
- # Initial data passed into the constructor overrides defaults.
- if name in form_instance.initial:
- data += unicode(form_instance.initial[name])
- elif name in form_instance.fields and form_instance.fields[name].initial is not None:
- data += unicode(form_instance.fields[name].initial)
+ data = ""
+ for name in secret_fields:
+ if hasattr(form_instance, 'cleaned_data'):
+ if name in form_instance.cleaned_data:
+ data += unicode(form_instance.cleaned_data[name])
+ else:
+ # Initial data passed into the constructor overrides defaults.
+ if name in form_instance.initial:
+ data += unicode(form_instance.initial[name])
+ elif name in form_instance.fields and form_instance.fields[name].initial is not None:
+ data += unicode(form_instance.fields[name].initial)
- secret = get_hexdigest('sha1', settings.SECRET_KEY, data)
- return secret
+ secret = get_hexdigest('sha1', settings.SECRET_KEY, data)
+ return secret
def check_secret(form_instance, secret):
- """
- Returns true if received `secret` matches expected secret for form_instance.
- Used to verify IPN.
-
- """
- # @@@ add invoice & custom
- # secret_fields = ['business', 'item_name']
- return make_secret(form_instance) == secret
+ """
+ Returns true if received `secret` matches expected secret for form_instance.
+ Used to verify IPN.
+
+ """
+ # @@@ add invoice & custom
+ # secret_fields = ['business', 'item_name']
+ return make_secret(form_instance) == secret
diff --git a/paypal/standard/ipn/admin.py b/paypal/standard/ipn/admin.py
index 173c97c..06f91e6 100644
--- a/paypal/standard/ipn/admin.py
+++ b/paypal/standard/ipn/admin.py
@@ -5,65 +5,65 @@
class PayPalIPNAdmin(admin.ModelAdmin):
- date_hierarchy = 'payment_date'
- fieldsets = (
- (None, {
- "fields": [
- "flag", "txn_id", "txn_type", "payment_status", "payment_date",
- "transaction_entity", "reason_code", "pending_reason",
- "mc_gross", "mc_fee", "auth_status", "auth_amount", "auth_exp",
- "auth_id"
- ]
- }),
- ("Address", {
- "description": "The address of the Buyer.",
- 'classes': ('collapse',),
- "fields": [
- "address_city", "address_country", "address_country_code",
- "address_name", "address_state", "address_status",
- "address_street", "address_zip"
- ]
- }),
- ("Buyer", {
- "description": "The information about the Buyer.",
- 'classes': ('collapse',),
- "fields": [
- "first_name", "last_name", "payer_business_name", "payer_email",
- "payer_id", "payer_status", "contact_phone", "residence_country"
- ]
- }),
- ("Seller", {
- "description": "The information about the Seller.",
- 'classes': ('collapse',),
- "fields": [
- "business", "item_name", "item_number", "quantity",
- "receiver_email", "receiver_id", "custom", "invoice", "memo"
- ]
- }),
- ("Recurring", {
- "description": "Information about recurring Payments.",
- "classes": ("collapse",),
- "fields": [
- "profile_status", "initial_payment_amount", "amount_per_cycle",
- "outstanding_balance", "period_type", "product_name",
- "product_type", "recurring_payment_id", "receipt_id",
- "next_payment_date"
- ]
- }),
- ("Admin", {
- "description": "Additional Info.",
- "classes": ('collapse',),
- "fields": [
- "test_ipn", "ipaddress", "query", "response", "flag_code",
- "flag_info"
- ]
- }),
- )
- list_display = [
- "__unicode__", "flag", "flag_info", "invoice", "custom",
- "payment_status", "created_at"
- ]
- search_fields = ["txn_id", "recurring_payment_id"]
+ date_hierarchy = 'payment_date'
+ fieldsets = (
+ (None, {
+ "fields": [
+ "flag", "txn_id", "txn_type", "payment_status", "payment_date",
+ "transaction_entity", "reason_code", "pending_reason",
+ "mc_gross", "mc_fee", "auth_status", "auth_amount", "auth_exp",
+ "auth_id"
+ ]
+ }),
+ ("Address", {
+ "description": "The address of the Buyer.",
+ 'classes': ('collapse',),
+ "fields": [
+ "address_city", "address_country", "address_country_code",
+ "address_name", "address_state", "address_status",
+ "address_street", "address_zip"
+ ]
+ }),
+ ("Buyer", {
+ "description": "The information about the Buyer.",
+ 'classes': ('collapse',),
+ "fields": [
+ "first_name", "last_name", "payer_business_name", "payer_email",
+ "payer_id", "payer_status", "contact_phone", "residence_country"
+ ]
+ }),
+ ("Seller", {
+ "description": "The information about the Seller.",
+ 'classes': ('collapse',),
+ "fields": [
+ "business", "item_name", "item_number", "quantity",
+ "receiver_email", "receiver_id", "custom", "invoice", "memo"
+ ]
+ }),
+ ("Recurring", {
+ "description": "Information about recurring Payments.",
+ "classes": ("collapse",),
+ "fields": [
+ "profile_status", "initial_payment_amount", "amount_per_cycle",
+ "outstanding_balance", "period_type", "product_name",
+ "product_type", "recurring_payment_id", "receipt_id",
+ "next_payment_date"
+ ]
+ }),
+ ("Admin", {
+ "description": "Additional Info.",
+ "classes": ('collapse',),
+ "fields": [
+ "test_ipn", "ipaddress", "query", "response", "flag_code",
+ "flag_info"
+ ]
+ }),
+ )
+ list_display = [
+ "__unicode__", "flag", "flag_info", "invoice", "custom",
+ "payment_status", "created_at"
+ ]
+ search_fields = ["txn_id", "recurring_payment_id"]
admin.site.register(PayPalIPN, PayPalIPNAdmin)
\ No newline at end of file
diff --git a/paypal/standard/ipn/forms.py b/paypal/standard/ipn/forms.py
index 8df7327..2cb2ccd 100644
--- a/paypal/standard/ipn/forms.py
+++ b/paypal/standard/ipn/forms.py
@@ -5,12 +5,12 @@
class PayPalIPNForm(PayPalStandardBaseForm):
- """
- Form used to receive and record PayPal IPN notifications.
-
- PayPal IPN test tool:
- https://developer.paypal.com/us/cgi-bin/devscr?cmd=_tools-session
- """
- class Meta:
- model = PayPalIPN
+ """
+ Form used to receive and record PayPal IPN notifications.
+
+ PayPal IPN test tool:
+ https://developer.paypal.com/us/cgi-bin/devscr?cmd=_tools-session
+ """
+ class Meta:
+ model = PayPalIPN
diff --git a/paypal/standard/ipn/migrations/0001_first_migration.py b/paypal/standard/ipn/migrations/0001_first_migration.py
index 54da912..7fe4162 100644
--- a/paypal/standard/ipn/migrations/0001_first_migration.py
+++ b/paypal/standard/ipn/migrations/0001_first_migration.py
@@ -3,242 +3,242 @@
from south.db import db
from paypal.standard.ipn.models import *
-class Migration:
- def forwards(self, orm):
- # Adding model 'PayPalIPN'
- db.create_table('paypal_ipn', (
- ('id', models.AutoField(primary_key=True)),
- ('business', models.CharField(max_length=127, blank=True)),
- ('charset', models.CharField(max_length=32, blank=True)),
- ('custom', models.CharField(max_length=255, blank=True)),
- ('notify_version', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('parent_txn_id', models.CharField("Parent Transaction ID", max_length=19, blank=True)),
- ('receiver_email', models.EmailField(max_length=127, blank=True)),
- ('receiver_id', models.CharField(max_length=127, blank=True)),
- ('residence_country', models.CharField(max_length=2, blank=True)),
- ('test_ipn', models.BooleanField(default=False, blank=True)),
- ('txn_id', models.CharField("Transaction ID", max_length=19, blank=True)),
- ('txn_type', models.CharField("Transaction Type", max_length=128, blank=True)),
- ('verify_sign', models.CharField(max_length=255, blank=True)),
- ('address_country', models.CharField(max_length=64, blank=True)),
- ('address_city', models.CharField(max_length=40, blank=True)),
- ('address_country_code', models.CharField(max_length=64, blank=True)),
- ('address_name', models.CharField(max_length=128, blank=True)),
- ('address_state', models.CharField(max_length=40, blank=True)),
- ('address_status', models.CharField(max_length=11, blank=True)),
- ('address_street', models.CharField(max_length=200, blank=True)),
- ('address_zip', models.CharField(max_length=20, blank=True)),
- ('contact_phone', models.CharField(max_length=20, blank=True)),
- ('first_name', models.CharField(max_length=64, blank=True)),
- ('last_name', models.CharField(max_length=64, blank=True)),
- ('payer_business_name', models.CharField(max_length=127, blank=True)),
- ('payer_email', models.CharField(max_length=127, blank=True)),
- ('payer_id', models.CharField(max_length=13, blank=True)),
- ('auth_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('auth_exp', models.CharField(max_length=28, blank=True)),
- ('auth_id', models.CharField(max_length=19, blank=True)),
- ('auth_status', models.CharField(max_length=9, blank=True)),
- ('exchange_rate', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=16, blank=True)),
- ('invoice', models.CharField(max_length=127, blank=True)),
- ('item_name', models.CharField(max_length=127, blank=True)),
- ('item_number', models.CharField(max_length=127, blank=True)),
- ('mc_currency', models.CharField(default='USD', max_length=32, blank=True)),
- ('mc_fee', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_handling', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('memo', models.CharField(max_length=255, blank=True)),
- ('num_cart_items', models.IntegerField(default=0, null=True, blank=True)),
- ('option_name1', models.CharField(max_length=64, blank=True)),
- ('option_name2', models.CharField(max_length=64, blank=True)),
- ('payer_status', models.CharField(max_length=10, blank=True)),
- ('payment_date', models.DateTimeField(null=True, blank=True)),
- ('payment_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('payment_status', models.CharField(max_length=9, blank=True)),
- ('payment_type', models.CharField(max_length=7, blank=True)),
- ('pending_reason', models.CharField(max_length=14, blank=True)),
- ('protection_eligibility', models.CharField(max_length=32, blank=True)),
- ('quantity', models.IntegerField(default=1, null=True, blank=True)),
- ('reason_code', models.CharField(max_length=15, blank=True)),
- ('remaining_settle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('settle_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('settle_currency', models.CharField(max_length=32, blank=True)),
- ('shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('shipping_method', models.CharField(max_length=255, blank=True)),
- ('tax', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('transaction_entity', models.CharField(max_length=7, blank=True)),
- ('auction_buyer_id', models.CharField(max_length=64, blank=True)),
- ('auction_closing_date', models.DateTimeField(null=True, blank=True)),
- ('auction_multi_item', models.IntegerField(default=0, null=True, blank=True)),
- ('for_auction', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount_per_cycle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('initial_payment_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('next_payment_date', models.DateTimeField(null=True, blank=True)),
- ('outstanding_balance', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('payment_cycle', models.CharField(max_length=32, blank=True)),
- ('period_type', models.CharField(max_length=32, blank=True)),
- ('product_name', models.CharField(max_length=128, blank=True)),
- ('product_type', models.CharField(max_length=128, blank=True)),
- ('profile_status', models.CharField(max_length=32, blank=True)),
- ('recurring_payment_id', models.CharField(max_length=128, blank=True)),
- ('rp_invoice_id', models.CharField(max_length=127, blank=True)),
- ('time_created', models.DateTimeField(null=True, blank=True)),
- ('amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('password', models.CharField(max_length=24, blank=True)),
- ('period1', models.CharField(max_length=32, blank=True)),
- ('period2', models.CharField(max_length=32, blank=True)),
- ('period3', models.CharField(max_length=32, blank=True)),
- ('reattempt', models.CharField(max_length=1, blank=True)),
- ('recur_times', models.IntegerField(default=0, null=True, blank=True)),
- ('recurring', models.CharField(max_length=1, blank=True)),
- ('retry_at', models.DateTimeField(null=True, blank=True)),
- ('subscr_date', models.DateTimeField(null=True, blank=True)),
- ('subscr_effective', models.DateTimeField(null=True, blank=True)),
- ('subscr_id', models.CharField(max_length=19, blank=True)),
- ('username', models.CharField(max_length=64, blank=True)),
- ('case_creation_date', models.DateTimeField(null=True, blank=True)),
- ('case_id', models.CharField(max_length=14, blank=True)),
- ('case_type', models.CharField(max_length=24, blank=True)),
- ('receipt_id', models.CharField(max_length=64, blank=True)),
- ('currency_code', models.CharField(default='USD', max_length=32, blank=True)),
- ('handling_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('transaction_subject', models.CharField(max_length=255, blank=True)),
- ('ipaddress', models.IPAddressField(blank=True)),
- ('flag', models.BooleanField(default=False, blank=True)),
- ('flag_code', models.CharField(max_length=16, blank=True)),
- ('flag_info', models.TextField(blank=True)),
- ('query', models.TextField(blank=True)),
- ('response', models.TextField(blank=True)),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('updated_at', models.DateTimeField(auto_now=True)),
- ('from_view', models.CharField(max_length=6, null=True, blank=True)),
- ))
- db.send_create_signal('ipn', ['PayPalIPN'])
+class Migration:
+ def forwards(self, orm):
+ # Adding model 'PayPalIPN'
+ db.create_table('paypal_ipn', (
+ ('id', models.AutoField(primary_key=True)),
+ ('business', models.CharField(max_length=127, blank=True)),
+ ('charset', models.CharField(max_length=32, blank=True)),
+ ('custom', models.CharField(max_length=255, blank=True)),
+ ('notify_version', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('parent_txn_id', models.CharField("Parent Transaction ID", max_length=19, blank=True)),
+ ('receiver_email', models.EmailField(max_length=127, blank=True)),
+ ('receiver_id', models.CharField(max_length=127, blank=True)),
+ ('residence_country', models.CharField(max_length=2, blank=True)),
+ ('test_ipn', models.BooleanField(default=False, blank=True)),
+ ('txn_id', models.CharField("Transaction ID", max_length=19, blank=True)),
+ ('txn_type', models.CharField("Transaction Type", max_length=128, blank=True)),
+ ('verify_sign', models.CharField(max_length=255, blank=True)),
+ ('address_country', models.CharField(max_length=64, blank=True)),
+ ('address_city', models.CharField(max_length=40, blank=True)),
+ ('address_country_code', models.CharField(max_length=64, blank=True)),
+ ('address_name', models.CharField(max_length=128, blank=True)),
+ ('address_state', models.CharField(max_length=40, blank=True)),
+ ('address_status', models.CharField(max_length=11, blank=True)),
+ ('address_street', models.CharField(max_length=200, blank=True)),
+ ('address_zip', models.CharField(max_length=20, blank=True)),
+ ('contact_phone', models.CharField(max_length=20, blank=True)),
+ ('first_name', models.CharField(max_length=64, blank=True)),
+ ('last_name', models.CharField(max_length=64, blank=True)),
+ ('payer_business_name', models.CharField(max_length=127, blank=True)),
+ ('payer_email', models.CharField(max_length=127, blank=True)),
+ ('payer_id', models.CharField(max_length=13, blank=True)),
+ ('auth_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('auth_exp', models.CharField(max_length=28, blank=True)),
+ ('auth_id', models.CharField(max_length=19, blank=True)),
+ ('auth_status', models.CharField(max_length=9, blank=True)),
+ ('exchange_rate', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=16, blank=True)),
+ ('invoice', models.CharField(max_length=127, blank=True)),
+ ('item_name', models.CharField(max_length=127, blank=True)),
+ ('item_number', models.CharField(max_length=127, blank=True)),
+ ('mc_currency', models.CharField(default='USD', max_length=32, blank=True)),
+ ('mc_fee', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_handling', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('memo', models.CharField(max_length=255, blank=True)),
+ ('num_cart_items', models.IntegerField(default=0, null=True, blank=True)),
+ ('option_name1', models.CharField(max_length=64, blank=True)),
+ ('option_name2', models.CharField(max_length=64, blank=True)),
+ ('payer_status', models.CharField(max_length=10, blank=True)),
+ ('payment_date', models.DateTimeField(null=True, blank=True)),
+ ('payment_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('payment_status', models.CharField(max_length=9, blank=True)),
+ ('payment_type', models.CharField(max_length=7, blank=True)),
+ ('pending_reason', models.CharField(max_length=14, blank=True)),
+ ('protection_eligibility', models.CharField(max_length=32, blank=True)),
+ ('quantity', models.IntegerField(default=1, null=True, blank=True)),
+ ('reason_code', models.CharField(max_length=15, blank=True)),
+ ('remaining_settle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('settle_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('settle_currency', models.CharField(max_length=32, blank=True)),
+ ('shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('shipping_method', models.CharField(max_length=255, blank=True)),
+ ('tax', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('transaction_entity', models.CharField(max_length=7, blank=True)),
+ ('auction_buyer_id', models.CharField(max_length=64, blank=True)),
+ ('auction_closing_date', models.DateTimeField(null=True, blank=True)),
+ ('auction_multi_item', models.IntegerField(default=0, null=True, blank=True)),
+ ('for_auction', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount_per_cycle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('initial_payment_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('next_payment_date', models.DateTimeField(null=True, blank=True)),
+ ('outstanding_balance', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('payment_cycle', models.CharField(max_length=32, blank=True)),
+ ('period_type', models.CharField(max_length=32, blank=True)),
+ ('product_name', models.CharField(max_length=128, blank=True)),
+ ('product_type', models.CharField(max_length=128, blank=True)),
+ ('profile_status', models.CharField(max_length=32, blank=True)),
+ ('recurring_payment_id', models.CharField(max_length=128, blank=True)),
+ ('rp_invoice_id', models.CharField(max_length=127, blank=True)),
+ ('time_created', models.DateTimeField(null=True, blank=True)),
+ ('amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('password', models.CharField(max_length=24, blank=True)),
+ ('period1', models.CharField(max_length=32, blank=True)),
+ ('period2', models.CharField(max_length=32, blank=True)),
+ ('period3', models.CharField(max_length=32, blank=True)),
+ ('reattempt', models.CharField(max_length=1, blank=True)),
+ ('recur_times', models.IntegerField(default=0, null=True, blank=True)),
+ ('recurring', models.CharField(max_length=1, blank=True)),
+ ('retry_at', models.DateTimeField(null=True, blank=True)),
+ ('subscr_date', models.DateTimeField(null=True, blank=True)),
+ ('subscr_effective', models.DateTimeField(null=True, blank=True)),
+ ('subscr_id', models.CharField(max_length=19, blank=True)),
+ ('username', models.CharField(max_length=64, blank=True)),
+ ('case_creation_date', models.DateTimeField(null=True, blank=True)),
+ ('case_id', models.CharField(max_length=14, blank=True)),
+ ('case_type', models.CharField(max_length=24, blank=True)),
+ ('receipt_id', models.CharField(max_length=64, blank=True)),
+ ('currency_code', models.CharField(default='USD', max_length=32, blank=True)),
+ ('handling_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('transaction_subject', models.CharField(max_length=255, blank=True)),
+ ('ipaddress', models.IPAddressField(blank=True)),
+ ('flag', models.BooleanField(default=False, blank=True)),
+ ('flag_code', models.CharField(max_length=16, blank=True)),
+ ('flag_info', models.TextField(blank=True)),
+ ('query', models.TextField(blank=True)),
+ ('response', models.TextField(blank=True)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('updated_at', models.DateTimeField(auto_now=True)),
+ ('from_view', models.CharField(max_length=6, null=True, blank=True)),
+ ))
+ db.send_create_signal('ipn', ['PayPalIPN'])
- def backwards(self, orm):
- # Deleting model 'PayPalIPN'
- db.delete_table('paypal_ipn')
+ def backwards(self, orm):
+ # Deleting model 'PayPalIPN'
+ db.delete_table('paypal_ipn')
- models = {
- 'ipn.paypalipn': {
- 'Meta': {'db_table': '"paypal_ipn"'},
- 'address_city': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
- 'address_country': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'address_country_code': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'address_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'address_state': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
- 'address_status': ('models.CharField', [], {'max_length': '11', 'blank': 'True'}),
- 'address_street': ('models.CharField', [], {'max_length': '200', 'blank': 'True'}),
- 'address_zip': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
- 'amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount_per_cycle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'auction_buyer_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'auction_closing_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'auction_multi_item': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
- 'auth_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'auth_exp': ('models.CharField', [], {'max_length': '28', 'blank': 'True'}),
- 'auth_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
- 'auth_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
- 'business': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'case_creation_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'case_id': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
- 'case_type': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
- 'charset': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'contact_phone': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
- 'created_at': ('models.DateTimeField', [], {'auto_now_add': 'True'}),
- 'currency_code': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
- 'custom': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'exchange_rate': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16', 'blank': 'True'}),
- 'first_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'flag': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
- 'flag_code': ('models.CharField', [], {'max_length': '16', 'blank': 'True'}),
- 'flag_info': ('models.TextField', [], {'blank': 'True'}),
- 'for_auction': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'from_view': ('models.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
- 'handling_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'id': ('models.AutoField', [], {'primary_key': 'True'}),
- 'initial_payment_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'invoice': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'ipaddress': ('models.IPAddressField', [], {'blank': 'True'}),
- 'item_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'item_number': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'last_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'mc_amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_currency': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
- 'mc_fee': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_handling': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'memo': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'next_payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'notify_version': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'num_cart_items': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
- 'option_name1': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'option_name2': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'outstanding_balance': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'parent_txn_id': ('models.CharField', ['"Parent Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
- 'password': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
- 'payer_business_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'payer_email': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'payer_id': ('models.CharField', [], {'max_length': '13', 'blank': 'True'}),
- 'payer_status': ('models.CharField', [], {'max_length': '10', 'blank': 'True'}),
- 'payment_cycle': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'payment_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'payment_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
- 'payment_type': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
- 'pending_reason': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
- 'period1': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'period2': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'period3': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'period_type': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'product_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'product_type': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'profile_status': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'protection_eligibility': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'quantity': ('models.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}),
- 'query': ('models.TextField', [], {'blank': 'True'}),
- 'reason_code': ('models.CharField', [], {'max_length': '15', 'blank': 'True'}),
- 'reattempt': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
- 'receipt_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'receiver_email': ('models.EmailField', [], {'max_length': '127', 'blank': 'True'}),
- 'receiver_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'recur_times': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
- 'recurring': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
- 'recurring_payment_id': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'remaining_settle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'residence_country': ('models.CharField', [], {'max_length': '2', 'blank': 'True'}),
- 'response': ('models.TextField', [], {'blank': 'True'}),
- 'retry_at': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'rp_invoice_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'settle_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'settle_currency': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'shipping_method': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'subscr_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'subscr_effective': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'subscr_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
- 'tax': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'test_ipn': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
- 'time_created': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'transaction_entity': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
- 'transaction_subject': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'txn_id': ('models.CharField', ['"Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
- 'txn_type': ('models.CharField', ['"Transaction Type"'], {'max_length': '128', 'blank': 'True'}),
- 'updated_at': ('models.DateTimeField', [], {'auto_now': 'True'}),
- 'username': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'verify_sign': ('models.CharField', [], {'max_length': '255', 'blank': 'True'})
- }
- }
- complete_apps = ['ipn']
+ models = {
+ 'ipn.paypalipn': {
+ 'Meta': {'db_table': '"paypal_ipn"'},
+ 'address_city': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
+ 'address_country': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'address_country_code': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'address_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'address_state': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
+ 'address_status': ('models.CharField', [], {'max_length': '11', 'blank': 'True'}),
+ 'address_street': ('models.CharField', [], {'max_length': '200', 'blank': 'True'}),
+ 'address_zip': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
+ 'amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount_per_cycle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'auction_buyer_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'auction_closing_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'auction_multi_item': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
+ 'auth_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'auth_exp': ('models.CharField', [], {'max_length': '28', 'blank': 'True'}),
+ 'auth_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
+ 'auth_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
+ 'business': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'case_creation_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'case_id': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
+ 'case_type': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
+ 'charset': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'contact_phone': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
+ 'created_at': ('models.DateTimeField', [], {'auto_now_add': 'True'}),
+ 'currency_code': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
+ 'custom': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'exchange_rate': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16', 'blank': 'True'}),
+ 'first_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'flag': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'flag_code': ('models.CharField', [], {'max_length': '16', 'blank': 'True'}),
+ 'flag_info': ('models.TextField', [], {'blank': 'True'}),
+ 'for_auction': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'from_view': ('models.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
+ 'handling_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'initial_payment_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'invoice': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'ipaddress': ('models.IPAddressField', [], {'blank': 'True'}),
+ 'item_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'item_number': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'last_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'mc_amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_currency': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
+ 'mc_fee': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_handling': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'memo': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'next_payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'notify_version': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'num_cart_items': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
+ 'option_name1': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'option_name2': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'outstanding_balance': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'parent_txn_id': ('models.CharField', ['"Parent Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
+ 'password': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
+ 'payer_business_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'payer_email': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'payer_id': ('models.CharField', [], {'max_length': '13', 'blank': 'True'}),
+ 'payer_status': ('models.CharField', [], {'max_length': '10', 'blank': 'True'}),
+ 'payment_cycle': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'payment_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'payment_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
+ 'payment_type': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
+ 'pending_reason': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
+ 'period1': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'period2': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'period3': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'period_type': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'product_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'product_type': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'profile_status': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'protection_eligibility': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'quantity': ('models.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}),
+ 'query': ('models.TextField', [], {'blank': 'True'}),
+ 'reason_code': ('models.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'reattempt': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
+ 'receipt_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'receiver_email': ('models.EmailField', [], {'max_length': '127', 'blank': 'True'}),
+ 'receiver_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'recur_times': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
+ 'recurring': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
+ 'recurring_payment_id': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'remaining_settle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'residence_country': ('models.CharField', [], {'max_length': '2', 'blank': 'True'}),
+ 'response': ('models.TextField', [], {'blank': 'True'}),
+ 'retry_at': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'rp_invoice_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'settle_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'settle_currency': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'shipping_method': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'subscr_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'subscr_effective': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'subscr_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
+ 'tax': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'test_ipn': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'time_created': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'transaction_entity': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
+ 'transaction_subject': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'txn_id': ('models.CharField', ['"Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
+ 'txn_type': ('models.CharField', ['"Transaction Type"'], {'max_length': '128', 'blank': 'True'}),
+ 'updated_at': ('models.DateTimeField', [], {'auto_now': 'True'}),
+ 'username': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'verify_sign': ('models.CharField', [], {'max_length': '255', 'blank': 'True'})
+ }
+ }
+ complete_apps = ['ipn']
diff --git a/paypal/standard/ipn/models.py b/paypal/standard/ipn/models.py
index 9495463..cc9cb5a 100644
--- a/paypal/standard/ipn/models.py
+++ b/paypal/standard/ipn/models.py
@@ -6,49 +6,49 @@
class PayPalIPN(PayPalStandardBase):
- """Logs PayPal IPN interactions."""
- format = u""
+ """Logs PayPal IPN interactions."""
+ format = u""
- class Meta:
- db_table = "paypal_ipn"
- verbose_name = "PayPal IPN"
+ class Meta:
+ db_table = "paypal_ipn"
+ verbose_name = "PayPal IPN"
- def _postback(self):
- """Perform PayPal Postback validation."""
- return urllib2.urlopen(self.get_endpoint(), "cmd=_notify-validate&%s" % self.query).read()
-
- def _verify_postback(self):
- if self.response != "VERIFIED":
- self.set_flag("Invalid postback. (%s)" % self.response)
-
- def send_signals(self):
- """Shout for the world to hear whether a txn was successful."""
- # Transaction signals:
- if self.is_transaction():
- if self.flag:
- payment_was_flagged.send(sender=self)
- else:
- payment_was_successful.send(sender=self)
- # Recurring payment signals:
- # XXX: Should these be merged with subscriptions?
- elif self.is_recurring():
- if self.is_recurring_create():
- recurring_create.send(sender=self)
- elif self.is_recurring_payment():
- recurring_payment.send(sender=self)
- elif self.is_recurring_cancel():
- recurring_cancel.send(sender=self)
- elif self.is_recurring_skipped():
- recurring_skipped.send(sender=self)
- elif self.is_recurring_failed():
- recurring_failed.send(sender=self)
- # Subscription signals:
- else:
- if self.is_subscription_cancellation():
- subscription_cancel.send(sender=self)
- elif self.is_subscription_signup():
- subscription_signup.send(sender=self)
- elif self.is_subscription_end_of_term():
- subscription_eot.send(sender=self)
- elif self.is_subscription_modified():
- subscription_modify.send(sender=self)
\ No newline at end of file
+ def _postback(self):
+ """Perform PayPal Postback validation."""
+ return urllib2.urlopen(self.get_endpoint(), "cmd=_notify-validate&%s" % self.query).read()
+
+ def _verify_postback(self):
+ if self.response != "VERIFIED":
+ self.set_flag("Invalid postback. (%s)" % self.response)
+
+ def send_signals(self):
+ """Shout for the world to hear whether a txn was successful."""
+ # Transaction signals:
+ if self.is_transaction():
+ if self.flag:
+ payment_was_flagged.send(sender=self)
+ else:
+ payment_was_successful.send(sender=self)
+ # Recurring payment signals:
+ # XXX: Should these be merged with subscriptions?
+ elif self.is_recurring():
+ if self.is_recurring_create():
+ recurring_create.send(sender=self)
+ elif self.is_recurring_payment():
+ recurring_payment.send(sender=self)
+ elif self.is_recurring_cancel():
+ recurring_cancel.send(sender=self)
+ elif self.is_recurring_skipped():
+ recurring_skipped.send(sender=self)
+ elif self.is_recurring_failed():
+ recurring_failed.send(sender=self)
+ # Subscription signals:
+ else:
+ if self.is_subscription_cancellation():
+ subscription_cancel.send(sender=self)
+ elif self.is_subscription_signup():
+ subscription_signup.send(sender=self)
+ elif self.is_subscription_end_of_term():
+ subscription_eot.send(sender=self)
+ elif self.is_subscription_modified():
+ subscription_modify.send(sender=self)
\ No newline at end of file
diff --git a/paypal/standard/ipn/tests/test_ipn.py b/paypal/standard/ipn/tests/test_ipn.py
index 2db0893..44c9b54 100644
--- a/paypal/standard/ipn/tests/test_ipn.py
+++ b/paypal/standard/ipn/tests/test_ipn.py
@@ -6,220 +6,220 @@
from paypal.standard.models import ST_PP_CANCELLED
from paypal.standard.ipn.models import PayPalIPN
from paypal.standard.ipn.signals import (payment_was_successful,
- payment_was_flagged, recurring_skipped, recurring_failed,
- recurring_create, recurring_payment, recurring_cancel)
+ payment_was_flagged, recurring_skipped, recurring_failed,
+ recurring_create, recurring_payment, recurring_cancel)
IPN_POST_PARAMS = {
- "protection_eligibility": "Ineligible",
- "last_name": "User",
- "txn_id": "51403485VH153354B",
- "receiver_email": settings.PAYPAL_RECEIVER_EMAIL,
- "payment_status": "Completed",
- "payment_gross": "10.00",
- "tax": "0.00",
- "residence_country": "US",
- "invoice": "0004",
- "payer_status": "verified",
- "txn_type": "express_checkout",
- "handling_amount": "0.00",
- "payment_date": "23:04:06 Feb 02, 2009 PST",
- "first_name": "Test",
- "item_name": "",
- "charset": "windows-1252",
- "custom": "website_id=13&user_id=21",
- "notify_version": "2.6",
- "transaction_subject": "",
- "test_ipn": "1",
- "item_number": "",
- "receiver_id": "258DLEHY2BDK6",
- "payer_id": "BN5JZ2V7MLEV4",
- "verify_sign": "An5ns1Kso7MWUdW4ErQKJJJ4qi4-AqdZy6dD.sGO3sDhTf1wAbuO2IZ7",
- "payment_fee": "0.59",
- "mc_fee": "0.59",
- "mc_currency": "USD",
- "shipping": "0.00",
- "payer_email": "bishan_1233269544_per@gmail.com",
- "payment_type": "instant",
- "mc_gross": "10.00",
- "quantity": "1",
+ "protection_eligibility": "Ineligible",
+ "last_name": "User",
+ "txn_id": "51403485VH153354B",
+ "receiver_email": settings.PAYPAL_RECEIVER_EMAIL,
+ "payment_status": "Completed",
+ "payment_gross": "10.00",
+ "tax": "0.00",
+ "residence_country": "US",
+ "invoice": "0004",
+ "payer_status": "verified",
+ "txn_type": "express_checkout",
+ "handling_amount": "0.00",
+ "payment_date": "23:04:06 Feb 02, 2009 PST",
+ "first_name": "Test",
+ "item_name": "",
+ "charset": "windows-1252",
+ "custom": "website_id=13&user_id=21",
+ "notify_version": "2.6",
+ "transaction_subject": "",
+ "test_ipn": "1",
+ "item_number": "",
+ "receiver_id": "258DLEHY2BDK6",
+ "payer_id": "BN5JZ2V7MLEV4",
+ "verify_sign": "An5ns1Kso7MWUdW4ErQKJJJ4qi4-AqdZy6dD.sGO3sDhTf1wAbuO2IZ7",
+ "payment_fee": "0.59",
+ "mc_fee": "0.59",
+ "mc_currency": "USD",
+ "shipping": "0.00",
+ "payer_email": "bishan_1233269544_per@gmail.com",
+ "payment_type": "instant",
+ "mc_gross": "10.00",
+ "quantity": "1",
}
-class IPNTest(TestCase):
- urls = 'paypal.standard.ipn.tests.test_urls'
-
- def setUp(self):
- self.old_debug = settings.DEBUG
- settings.DEBUG = True
-
- # Monkey patch over PayPalIPN to make it get a VERFIED response.
- self.old_postback = PayPalIPN._postback
- PayPalIPN._postback = lambda self: "VERIFIED"
-
- self.payment_was_successful_receivers = payment_was_successful.receivers
- self.payment_was_flagged_receivers = payment_was_flagged.receivers
- self.recurring_skipped_receivers = recurring_skipped.receivers
- self.recurring_failed_receivers = recurring_failed.receivers
- self.recurring_create_receivers = recurring_create.receivers
- self.recurring_payment_receivers = recurring_payment.receivers
- self.recurring_cancel_receivers = recurring_cancel.receivers
-
- payment_was_successful.receivers = []
- payment_was_flagged.receivers = []
- recurring_skipped.receivers = []
- recurring_failed.receivers = []
- recurring_create.receivers = []
- recurring_payment.receivers = []
- recurring_cancel.receivers = []
-
-
- def tearDown(self):
- settings.DEBUG = self.old_debug
- PayPalIPN._postback = self.old_postback
-
- payment_was_successful.receivers =self.payment_was_successful_receivers
- payment_was_flagged.receivers = self.payment_was_flagged_receivers
- recurring_skipped.receivers = self.recurring_skipped_receivers
- recurring_failed.receivers = self.recurring_failed_receivers
- recurring_create.receivers = self.recurring_create_receivers
- recurring_payment.receivers = self.recurring_payment_receivers
- recurring_cancel.receivers = self.recurring_cancel_receivers
-
-
- def assertGotSignal(self, signal, flagged, params=IPN_POST_PARAMS):
- # Check the signal was sent. These get lost if they don't reference self.
- self.got_signal = False
- self.signal_obj = None
-
- def handle_signal(sender, **kwargs):
- self.got_signal = True
- self.signal_obj = sender
- signal.connect(handle_signal)
-
- response = self.client.post("/ipn/", params)
- self.assertEqual(response.status_code, 200)
- ipns = PayPalIPN.objects.all()
- self.assertEqual(len(ipns), 1)
- ipn_obj = ipns[0]
- self.assertEqual(ipn_obj.flag, flagged)
-
- self.assertTrue(self.got_signal)
- self.assertEqual(self.signal_obj, ipn_obj)
-
- def test_correct_ipn(self):
- self.assertGotSignal(payment_was_successful, False)
-
- def test_failed_ipn(self):
- PayPalIPN._postback = lambda self: "INVALID"
- self.assertGotSignal(payment_was_flagged, True)
-
- def assertFlagged(self, updates, flag_info):
- params = IPN_POST_PARAMS.copy()
- params.update(updates)
- response = self.client.post("/ipn/", params)
- self.assertEqual(response.status_code, 200)
- ipn_obj = PayPalIPN.objects.all()[0]
- self.assertEqual(ipn_obj.flag, True)
- self.assertEqual(ipn_obj.flag_info, flag_info)
-
- def test_incorrect_receiver_email(self):
- update = {"receiver_email": "incorrect_email@someotherbusiness.com"}
- flag_info = "Invalid receiver_email. (incorrect_email@someotherbusiness.com)"
- self.assertFlagged(update, flag_info)
-
- def test_invalid_payment_status(self):
- update = {"payment_status": "Failed"}
- flag_info = u"Invalid payment_status. (Failed)"
- self.assertFlagged(update, flag_info)
-
- def test_vaid_payment_status_cancelled(self):
- update = {"payment_status": ST_PP_CANCELLED}
- params = IPN_POST_PARAMS.copy()
- params.update(update)
- response = self.client.post("/ipn/", params)
- self.assertEqual(response.status_code, 200)
- ipn_obj = PayPalIPN.objects.all()[0]
- self.assertEqual(ipn_obj.flag, False)
-
-
- def test_duplicate_txn_id(self):
- self.client.post("/ipn/", IPN_POST_PARAMS)
- self.client.post("/ipn/", IPN_POST_PARAMS)
- self.assertEqual(len(PayPalIPN.objects.all()), 2)
- ipn_obj = PayPalIPN.objects.order_by('-created_at', '-pk')[0]
- self.assertEqual(ipn_obj.flag, True)
- self.assertEqual(ipn_obj.flag_info, "Duplicate txn_id. (51403485VH153354B)")
-
- def test_recurring_payment_skipped_ipn(self):
- update = {
- "recurring_payment_id": "BN5JZ2V7MLEV4",
- "txn_type": "recurring_payment_skipped",
- "txn_id": ""
- }
- params = IPN_POST_PARAMS.copy()
- params.update(update)
-
- self.assertGotSignal(recurring_skipped, False, params)
-
- def test_recurring_payment_failed_ipn(self):
- update = {
- "recurring_payment_id": "BN5JZ2V7MLEV4",
- "txn_type": "recurring_payment_failed",
- "txn_id": ""
- }
- params = IPN_POST_PARAMS.copy()
- params.update(update)
-
- self.assertGotSignal(recurring_failed, False, params)
-
- def test_recurring_payment_create_ipn(self):
- update = {
- "recurring_payment_id": "BN5JZ2V7MLEV4",
- "txn_type": "recurring_payment_profile_created",
- "txn_id": ""
- }
- params = IPN_POST_PARAMS.copy()
- params.update(update)
-
- self.assertGotSignal(recurring_create, False, params)
-
- def test_recurring_payment_cancel_ipn(self):
- update = {
- "recurring_payment_id": "BN5JZ2V7MLEV4",
- "txn_type": "recurring_payment_profile_cancel",
- "txn_id": ""
- }
- params = IPN_POST_PARAMS.copy()
- params.update(update)
-
- self.assertGotSignal(recurring_cancel, False, params)
-
- def test_recurring_payment_ipn(self):
- """
- The wat the code is written in
- PayPalIPN.send_signals the recurring_payment
- will never be sent because the paypal ipn
- contains a txn_id, if this test failes you
- might break some compatibility
- """
- update = {
- "recurring_payment_id": "BN5JZ2V7MLEV4",
- "txn_type": "recurring_payment",
- }
- params = IPN_POST_PARAMS.copy()
- params.update(update)
-
- self.got_signal = False
- self.signal_obj = None
-
- def handle_signal(sender, **kwargs):
- self.got_signal = True
- self.signal_obj = sender
- recurring_payment.connect(handle_signal)
-
- response = self.client.post("/ipn/", params)
- self.assertEqual(response.status_code, 200)
- ipns = PayPalIPN.objects.all()
- self.assertEqual(len(ipns), 1)
- self.assertFalse(self.got_signal)
+class IPNTest(TestCase):
+ urls = 'paypal.standard.ipn.tests.test_urls'
+
+ def setUp(self):
+ self.old_debug = settings.DEBUG
+ settings.DEBUG = True
+
+ # Monkey patch over PayPalIPN to make it get a VERFIED response.
+ self.old_postback = PayPalIPN._postback
+ PayPalIPN._postback = lambda self: "VERIFIED"
+
+ self.payment_was_successful_receivers = payment_was_successful.receivers
+ self.payment_was_flagged_receivers = payment_was_flagged.receivers
+ self.recurring_skipped_receivers = recurring_skipped.receivers
+ self.recurring_failed_receivers = recurring_failed.receivers
+ self.recurring_create_receivers = recurring_create.receivers
+ self.recurring_payment_receivers = recurring_payment.receivers
+ self.recurring_cancel_receivers = recurring_cancel.receivers
+
+ payment_was_successful.receivers = []
+ payment_was_flagged.receivers = []
+ recurring_skipped.receivers = []
+ recurring_failed.receivers = []
+ recurring_create.receivers = []
+ recurring_payment.receivers = []
+ recurring_cancel.receivers = []
+
+
+ def tearDown(self):
+ settings.DEBUG = self.old_debug
+ PayPalIPN._postback = self.old_postback
+
+ payment_was_successful.receivers =self.payment_was_successful_receivers
+ payment_was_flagged.receivers = self.payment_was_flagged_receivers
+ recurring_skipped.receivers = self.recurring_skipped_receivers
+ recurring_failed.receivers = self.recurring_failed_receivers
+ recurring_create.receivers = self.recurring_create_receivers
+ recurring_payment.receivers = self.recurring_payment_receivers
+ recurring_cancel.receivers = self.recurring_cancel_receivers
+
+
+ def assertGotSignal(self, signal, flagged, params=IPN_POST_PARAMS):
+ # Check the signal was sent. These get lost if they don't reference self.
+ self.got_signal = False
+ self.signal_obj = None
+
+ def handle_signal(sender, **kwargs):
+ self.got_signal = True
+ self.signal_obj = sender
+ signal.connect(handle_signal)
+
+ response = self.client.post("/ipn/", params)
+ self.assertEqual(response.status_code, 200)
+ ipns = PayPalIPN.objects.all()
+ self.assertEqual(len(ipns), 1)
+ ipn_obj = ipns[0]
+ self.assertEqual(ipn_obj.flag, flagged)
+
+ self.assertTrue(self.got_signal)
+ self.assertEqual(self.signal_obj, ipn_obj)
+
+ def test_correct_ipn(self):
+ self.assertGotSignal(payment_was_successful, False)
+
+ def test_failed_ipn(self):
+ PayPalIPN._postback = lambda self: "INVALID"
+ self.assertGotSignal(payment_was_flagged, True)
+
+ def assertFlagged(self, updates, flag_info):
+ params = IPN_POST_PARAMS.copy()
+ params.update(updates)
+ response = self.client.post("/ipn/", params)
+ self.assertEqual(response.status_code, 200)
+ ipn_obj = PayPalIPN.objects.all()[0]
+ self.assertEqual(ipn_obj.flag, True)
+ self.assertEqual(ipn_obj.flag_info, flag_info)
+
+ def test_incorrect_receiver_email(self):
+ update = {"receiver_email": "incorrect_email@someotherbusiness.com"}
+ flag_info = "Invalid receiver_email. (incorrect_email@someotherbusiness.com)"
+ self.assertFlagged(update, flag_info)
+
+ def test_invalid_payment_status(self):
+ update = {"payment_status": "Failed"}
+ flag_info = u"Invalid payment_status. (Failed)"
+ self.assertFlagged(update, flag_info)
+
+ def test_vaid_payment_status_cancelled(self):
+ update = {"payment_status": ST_PP_CANCELLED}
+ params = IPN_POST_PARAMS.copy()
+ params.update(update)
+ response = self.client.post("/ipn/", params)
+ self.assertEqual(response.status_code, 200)
+ ipn_obj = PayPalIPN.objects.all()[0]
+ self.assertEqual(ipn_obj.flag, False)
+
+
+ def test_duplicate_txn_id(self):
+ self.client.post("/ipn/", IPN_POST_PARAMS)
+ self.client.post("/ipn/", IPN_POST_PARAMS)
+ self.assertEqual(len(PayPalIPN.objects.all()), 2)
+ ipn_obj = PayPalIPN.objects.order_by('-created_at', '-pk')[0]
+ self.assertEqual(ipn_obj.flag, True)
+ self.assertEqual(ipn_obj.flag_info, "Duplicate txn_id. (51403485VH153354B)")
+
+ def test_recurring_payment_skipped_ipn(self):
+ update = {
+ "recurring_payment_id": "BN5JZ2V7MLEV4",
+ "txn_type": "recurring_payment_skipped",
+ "txn_id": ""
+ }
+ params = IPN_POST_PARAMS.copy()
+ params.update(update)
+
+ self.assertGotSignal(recurring_skipped, False, params)
+
+ def test_recurring_payment_failed_ipn(self):
+ update = {
+ "recurring_payment_id": "BN5JZ2V7MLEV4",
+ "txn_type": "recurring_payment_failed",
+ "txn_id": ""
+ }
+ params = IPN_POST_PARAMS.copy()
+ params.update(update)
+
+ self.assertGotSignal(recurring_failed, False, params)
+
+ def test_recurring_payment_create_ipn(self):
+ update = {
+ "recurring_payment_id": "BN5JZ2V7MLEV4",
+ "txn_type": "recurring_payment_profile_created",
+ "txn_id": ""
+ }
+ params = IPN_POST_PARAMS.copy()
+ params.update(update)
+
+ self.assertGotSignal(recurring_create, False, params)
+
+ def test_recurring_payment_cancel_ipn(self):
+ update = {
+ "recurring_payment_id": "BN5JZ2V7MLEV4",
+ "txn_type": "recurring_payment_profile_cancel",
+ "txn_id": ""
+ }
+ params = IPN_POST_PARAMS.copy()
+ params.update(update)
+
+ self.assertGotSignal(recurring_cancel, False, params)
+
+ def test_recurring_payment_ipn(self):
+ """
+ The wat the code is written in
+ PayPalIPN.send_signals the recurring_payment
+ will never be sent because the paypal ipn
+ contains a txn_id, if this test failes you
+ might break some compatibility
+ """
+ update = {
+ "recurring_payment_id": "BN5JZ2V7MLEV4",
+ "txn_type": "recurring_payment",
+ }
+ params = IPN_POST_PARAMS.copy()
+ params.update(update)
+
+ self.got_signal = False
+ self.signal_obj = None
+
+ def handle_signal(sender, **kwargs):
+ self.got_signal = True
+ self.signal_obj = sender
+ recurring_payment.connect(handle_signal)
+
+ response = self.client.post("/ipn/", params)
+ self.assertEqual(response.status_code, 200)
+ ipns = PayPalIPN.objects.all()
+ self.assertEqual(len(ipns), 1)
+ self.assertFalse(self.got_signal)
diff --git a/paypal/standard/ipn/tests/test_urls.py b/paypal/standard/ipn/tests/test_urls.py
index 55d7f07..329f860 100644
--- a/paypal/standard/ipn/tests/test_urls.py
+++ b/paypal/standard/ipn/tests/test_urls.py
@@ -1,5 +1,5 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('paypal.standard.ipn.views',
- (r'^ipn/$', 'ipn'),
+ (r'^ipn/$', 'ipn'),
)
diff --git a/paypal/standard/ipn/urls.py b/paypal/standard/ipn/urls.py
index 9de742b..aa8f0e5 100644
--- a/paypal/standard/ipn/urls.py
+++ b/paypal/standard/ipn/urls.py
@@ -1,5 +1,5 @@
from django.conf.urls.defaults import *
-urlpatterns = patterns('paypal.standard.ipn.views',
- url(r'^$', 'ipn', name="paypal-ipn"),
+urlpatterns = patterns('paypal.standard.ipn.views',
+ url(r'^$', 'ipn', name="paypal-ipn"),
)
\ No newline at end of file
diff --git a/paypal/standard/ipn/views.py b/paypal/standard/ipn/views.py
index fb99967..bccf65a 100644
--- a/paypal/standard/ipn/views.py
+++ b/paypal/standard/ipn/views.py
@@ -10,52 +10,52 @@
@require_POST
@csrf_exempt
def ipn(request, item_check_callable=None):
- """
- PayPal IPN endpoint (notify_url).
- Used by both PayPal Payments Pro and Payments Standard to confirm transactions.
- http://tinyurl.com/d9vu9d
-
- PayPal IPN Simulator:
- https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session
- """
- #TODO: Clean up code so that we don't need to set None here and have a lot
- # of if checks just to determine if flag is set.
- flag = None
- ipn_obj = None
-
- # Clean up the data as PayPal sends some weird values such as "N/A"
- data = request.POST.copy()
- date_fields = ('time_created', 'payment_date', 'next_payment_date',
- 'subscr_date', 'subscr_effective')
- for date_field in date_fields:
- if data.get(date_field) == 'N/A':
- del data[date_field]
+ """
+ PayPal IPN endpoint (notify_url).
+ Used by both PayPal Payments Pro and Payments Standard to confirm transactions.
+ http://tinyurl.com/d9vu9d
+
+ PayPal IPN Simulator:
+ https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session
+ """
+ #TODO: Clean up code so that we don't need to set None here and have a lot
+ # of if checks just to determine if flag is set.
+ flag = None
+ ipn_obj = None
+
+ # Clean up the data as PayPal sends some weird values such as "N/A"
+ data = request.POST.copy()
+ date_fields = ('time_created', 'payment_date', 'next_payment_date',
+ 'subscr_date', 'subscr_effective')
+ for date_field in date_fields:
+ if data.get(date_field) == 'N/A':
+ del data[date_field]
- form = PayPalIPNForm(data)
- if form.is_valid():
- try:
- #When commit = False, object is returned without saving to DB.
- ipn_obj = form.save(commit = False)
- except Exception, e:
- flag = "Exception while processing. (%s)" % e
- else:
- flag = "Invalid form. (%s)" % form.errors
+ form = PayPalIPNForm(data)
+ if form.is_valid():
+ try:
+ #When commit = False, object is returned without saving to DB.
+ ipn_obj = form.save(commit = False)
+ except Exception, e:
+ flag = "Exception while processing. (%s)" % e
+ else:
+ flag = "Invalid form. (%s)" % form.errors
- if ipn_obj is None:
- ipn_obj = PayPalIPN()
-
- #Set query params and sender's IP address
- ipn_obj.initialize(request)
+ if ipn_obj is None:
+ ipn_obj = PayPalIPN()
+
+ #Set query params and sender's IP address
+ ipn_obj.initialize(request)
- if flag is not None:
- #We save errors in the flag field
- ipn_obj.set_flag(flag)
- else:
- # Secrets should only be used over SSL.
- if request.is_secure() and 'secret' in request.GET:
- ipn_obj.verify_secret(form, request.GET['secret'])
- else:
- ipn_obj.verify(item_check_callable)
+ if flag is not None:
+ #We save errors in the flag field
+ ipn_obj.set_flag(flag)
+ else:
+ # Secrets should only be used over SSL.
+ if request.is_secure() and 'secret' in request.GET:
+ ipn_obj.verify_secret(form, request.GET['secret'])
+ else:
+ ipn_obj.verify(item_check_callable)
- ipn_obj.save()
- return HttpResponse("OKAY")
+ ipn_obj.save()
+ return HttpResponse("OKAY")
diff --git a/paypal/standard/models.py b/paypal/standard/models.py
index c07e2fd..ab3ebdc 100644
--- a/paypal/standard/models.py
+++ b/paypal/standard/models.py
@@ -20,299 +20,299 @@
ST_PP_UNCLEARED = 'Uncleared'
try:
- from idmapper.models import SharedMemoryModel as Model
+ from idmapper.models import SharedMemoryModel as Model
except ImportError:
- Model = models.Model
+ Model = models.Model
class PayPalStandardBase(Model):
- """Meta class for common variables shared by IPN and PDT: http://tinyurl.com/cuq6sj"""
- # @@@ Might want to add all these one distant day.
- # FLAG_CODE_CHOICES = (
- # PAYMENT_STATUS_CHOICES = "Canceled_ Reversal Completed Denied Expired Failed Pending Processed Refunded Reversed Voided".split()
- PAYMENT_STATUS_CHOICES = (ST_PP_ACTIVE, ST_PP_CANCELLED, ST_PP_CLEARED, ST_PP_COMPLETED, ST_PP_DENIED, ST_PP_PAID, ST_PP_PENDING, ST_PP_PROCESSED, ST_PP_REFUSED, ST_PP_REVERSED, ST_PP_REWARDED, ST_PP_UNCLAIMED, ST_PP_UNCLEARED)
- # AUTH_STATUS_CHOICES = "Completed Pending Voided".split()
- # ADDRESS_STATUS_CHOICES = "confirmed unconfirmed".split()
- # PAYER_STATUS_CHOICES = "verified / unverified".split()
- # PAYMENT_TYPE_CHOICES = "echeck / instant.split()
- # PENDING_REASON = "address authorization echeck intl multi-currency unilateral upgrade verify other".split()
- # REASON_CODE = "chargeback guarantee buyer_complaint refund other".split()
- # TRANSACTION_ENTITY_CHOICES = "auth reauth order payment".split()
-
- # Transaction and Notification-Related Variables
- business = models.CharField(max_length=127, blank=True, help_text="Email where the money was sent.")
- charset=models.CharField(max_length=32, blank=True)
- custom = models.CharField(max_length=255, blank=True)
- notify_version = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- parent_txn_id = models.CharField("Parent Transaction ID", max_length=19, blank=True)
- receiver_email = models.EmailField(max_length=127, blank=True)
- receiver_id = models.CharField(max_length=127, blank=True) # 258DLEHY2BDK6
- residence_country = models.CharField(max_length=2, blank=True)
- test_ipn = models.BooleanField(default=False, blank=True)
- txn_id = models.CharField("Transaction ID", max_length=19, blank=True, help_text="PayPal transaction ID.", db_index=True)
- txn_type = models.CharField("Transaction Type", max_length=128, blank=True, help_text="PayPal transaction type.")
- verify_sign = models.CharField(max_length=255, blank=True)
-
- # Buyer Information Variables
- address_country = models.CharField(max_length=64, blank=True)
- address_city = models.CharField(max_length=40, blank=True)
- address_country_code = models.CharField(max_length=64, blank=True, help_text="ISO 3166")
- address_name = models.CharField(max_length=128, blank=True)
- address_state = models.CharField(max_length=40, blank=True)
- address_status = models.CharField(max_length=11, blank=True)
- address_street = models.CharField(max_length=200, blank=True)
- address_zip = models.CharField(max_length=20, blank=True)
- contact_phone = models.CharField(max_length=20, blank=True)
- first_name = models.CharField(max_length=64, blank=True)
- last_name = models.CharField(max_length=64, blank=True)
- payer_business_name = models.CharField(max_length=127, blank=True)
- payer_email = models.CharField(max_length=127, blank=True)
- payer_id = models.CharField(max_length=13, blank=True)
-
- # Payment Information Variables
- auth_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- auth_exp = models.CharField(max_length=28, blank=True)
- auth_id = models.CharField(max_length=19, blank=True)
- auth_status = models.CharField(max_length=9, blank=True)
- exchange_rate = models.DecimalField(max_digits=64, decimal_places=16, default=0, blank=True, null=True)
- invoice = models.CharField(max_length=127, blank=True)
- item_name = models.CharField(max_length=127, blank=True)
- item_number = models.CharField(max_length=127, blank=True)
- mc_currency = models.CharField(max_length=32, default="USD", blank=True)
- mc_fee = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- mc_gross = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- mc_handling = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- mc_shipping = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- memo = models.CharField(max_length=255, blank=True)
- num_cart_items = models.IntegerField(blank=True, default=0, null=True)
- option_name1 = models.CharField(max_length=64, blank=True)
- option_name2 = models.CharField(max_length=64, blank=True)
- payer_status = models.CharField(max_length=10, blank=True)
- payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- payment_gross = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- payment_status = models.CharField(max_length=9, blank=True)
- payment_type = models.CharField(max_length=7, blank=True)
- pending_reason = models.CharField(max_length=14, blank=True)
- protection_eligibility=models.CharField(max_length=32, blank=True)
- quantity = models.IntegerField(blank=True, default=1, null=True)
- reason_code = models.CharField(max_length=15, blank=True)
- remaining_settle = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- settle_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- settle_currency = models.CharField(max_length=32, blank=True)
- shipping = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- shipping_method = models.CharField(max_length=255, blank=True)
- tax = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- transaction_entity = models.CharField(max_length=7, blank=True)
-
- # Auction Variables
- auction_buyer_id = models.CharField(max_length=64, blank=True)
- auction_closing_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- auction_multi_item = models.IntegerField(blank=True, default=0, null=True)
- for_auction = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
-
- # Recurring Payments Variables
- amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- amount_per_cycle = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- initial_payment_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- next_payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- outstanding_balance = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- payment_cycle= models.CharField(max_length=32, blank=True) #Monthly
- period_type = models.CharField(max_length=32, blank=True)
- product_name = models.CharField(max_length=128, blank=True)
- product_type= models.CharField(max_length=128, blank=True)
- profile_status = models.CharField(max_length=32, blank=True)
- recurring_payment_id = models.CharField(max_length=128, blank=True) # I-FA4XVST722B9
- rp_invoice_id= models.CharField(max_length=127, blank=True) # 1335-7816-2936-1451
- time_created = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
-
- # Subscription Variables
- amount1 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- amount2 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- amount3 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- mc_amount1 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- mc_amount2 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- mc_amount3 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- password = models.CharField(max_length=24, blank=True)
- period1 = models.CharField(max_length=32, blank=True)
- period2 = models.CharField(max_length=32, blank=True)
- period3 = models.CharField(max_length=32, blank=True)
- reattempt = models.CharField(max_length=1, blank=True)
- recur_times = models.IntegerField(blank=True, default=0, null=True)
- recurring = models.CharField(max_length=1, blank=True)
- retry_at = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- subscr_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- subscr_effective = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- subscr_id = models.CharField(max_length=19, blank=True)
- username = models.CharField(max_length=64, blank=True)
-
- # Dispute Resolution Variables
- case_creation_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- case_id = models.CharField(max_length=14, blank=True)
- case_type = models.CharField(max_length=24, blank=True)
-
- # Variables not categorized
- receipt_id= models.CharField(max_length=64, blank=True) # 1335-7816-2936-1451
- currency_code = models.CharField(max_length=32, default="USD", blank=True)
- handling_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- transaction_subject = models.CharField(max_length=255, blank=True)
+ """Meta class for common variables shared by IPN and PDT: http://tinyurl.com/cuq6sj"""
+ # @@@ Might want to add all these one distant day.
+ # FLAG_CODE_CHOICES = (
+ # PAYMENT_STATUS_CHOICES = "Canceled_ Reversal Completed Denied Expired Failed Pending Processed Refunded Reversed Voided".split()
+ PAYMENT_STATUS_CHOICES = (ST_PP_ACTIVE, ST_PP_CANCELLED, ST_PP_CLEARED, ST_PP_COMPLETED, ST_PP_DENIED, ST_PP_PAID, ST_PP_PENDING, ST_PP_PROCESSED, ST_PP_REFUSED, ST_PP_REVERSED, ST_PP_REWARDED, ST_PP_UNCLAIMED, ST_PP_UNCLEARED)
+ # AUTH_STATUS_CHOICES = "Completed Pending Voided".split()
+ # ADDRESS_STATUS_CHOICES = "confirmed unconfirmed".split()
+ # PAYER_STATUS_CHOICES = "verified / unverified".split()
+ # PAYMENT_TYPE_CHOICES = "echeck / instant.split()
+ # PENDING_REASON = "address authorization echeck intl multi-currency unilateral upgrade verify other".split()
+ # REASON_CODE = "chargeback guarantee buyer_complaint refund other".split()
+ # TRANSACTION_ENTITY_CHOICES = "auth reauth order payment".split()
+
+ # Transaction and Notification-Related Variables
+ business = models.CharField(max_length=127, blank=True, help_text="Email where the money was sent.")
+ charset=models.CharField(max_length=32, blank=True)
+ custom = models.CharField(max_length=255, blank=True)
+ notify_version = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ parent_txn_id = models.CharField("Parent Transaction ID", max_length=19, blank=True)
+ receiver_email = models.EmailField(max_length=127, blank=True)
+ receiver_id = models.CharField(max_length=127, blank=True) # 258DLEHY2BDK6
+ residence_country = models.CharField(max_length=2, blank=True)
+ test_ipn = models.BooleanField(default=False, blank=True)
+ txn_id = models.CharField("Transaction ID", max_length=19, blank=True, help_text="PayPal transaction ID.", db_index=True)
+ txn_type = models.CharField("Transaction Type", max_length=128, blank=True, help_text="PayPal transaction type.")
+ verify_sign = models.CharField(max_length=255, blank=True)
+
+ # Buyer Information Variables
+ address_country = models.CharField(max_length=64, blank=True)
+ address_city = models.CharField(max_length=40, blank=True)
+ address_country_code = models.CharField(max_length=64, blank=True, help_text="ISO 3166")
+ address_name = models.CharField(max_length=128, blank=True)
+ address_state = models.CharField(max_length=40, blank=True)
+ address_status = models.CharField(max_length=11, blank=True)
+ address_street = models.CharField(max_length=200, blank=True)
+ address_zip = models.CharField(max_length=20, blank=True)
+ contact_phone = models.CharField(max_length=20, blank=True)
+ first_name = models.CharField(max_length=64, blank=True)
+ last_name = models.CharField(max_length=64, blank=True)
+ payer_business_name = models.CharField(max_length=127, blank=True)
+ payer_email = models.CharField(max_length=127, blank=True)
+ payer_id = models.CharField(max_length=13, blank=True)
+
+ # Payment Information Variables
+ auth_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ auth_exp = models.CharField(max_length=28, blank=True)
+ auth_id = models.CharField(max_length=19, blank=True)
+ auth_status = models.CharField(max_length=9, blank=True)
+ exchange_rate = models.DecimalField(max_digits=64, decimal_places=16, default=0, blank=True, null=True)
+ invoice = models.CharField(max_length=127, blank=True)
+ item_name = models.CharField(max_length=127, blank=True)
+ item_number = models.CharField(max_length=127, blank=True)
+ mc_currency = models.CharField(max_length=32, default="USD", blank=True)
+ mc_fee = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ mc_gross = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ mc_handling = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ mc_shipping = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ memo = models.CharField(max_length=255, blank=True)
+ num_cart_items = models.IntegerField(blank=True, default=0, null=True)
+ option_name1 = models.CharField(max_length=64, blank=True)
+ option_name2 = models.CharField(max_length=64, blank=True)
+ payer_status = models.CharField(max_length=10, blank=True)
+ payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ payment_gross = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ payment_status = models.CharField(max_length=9, blank=True)
+ payment_type = models.CharField(max_length=7, blank=True)
+ pending_reason = models.CharField(max_length=14, blank=True)
+ protection_eligibility=models.CharField(max_length=32, blank=True)
+ quantity = models.IntegerField(blank=True, default=1, null=True)
+ reason_code = models.CharField(max_length=15, blank=True)
+ remaining_settle = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ settle_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ settle_currency = models.CharField(max_length=32, blank=True)
+ shipping = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ shipping_method = models.CharField(max_length=255, blank=True)
+ tax = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ transaction_entity = models.CharField(max_length=7, blank=True)
+
+ # Auction Variables
+ auction_buyer_id = models.CharField(max_length=64, blank=True)
+ auction_closing_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ auction_multi_item = models.IntegerField(blank=True, default=0, null=True)
+ for_auction = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+
+ # Recurring Payments Variables
+ amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ amount_per_cycle = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ initial_payment_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ next_payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ outstanding_balance = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ payment_cycle= models.CharField(max_length=32, blank=True) #Monthly
+ period_type = models.CharField(max_length=32, blank=True)
+ product_name = models.CharField(max_length=128, blank=True)
+ product_type= models.CharField(max_length=128, blank=True)
+ profile_status = models.CharField(max_length=32, blank=True)
+ recurring_payment_id = models.CharField(max_length=128, blank=True) # I-FA4XVST722B9
+ rp_invoice_id= models.CharField(max_length=127, blank=True) # 1335-7816-2936-1451
+ time_created = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+
+ # Subscription Variables
+ amount1 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ amount2 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ amount3 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ mc_amount1 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ mc_amount2 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ mc_amount3 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ password = models.CharField(max_length=24, blank=True)
+ period1 = models.CharField(max_length=32, blank=True)
+ period2 = models.CharField(max_length=32, blank=True)
+ period3 = models.CharField(max_length=32, blank=True)
+ reattempt = models.CharField(max_length=1, blank=True)
+ recur_times = models.IntegerField(blank=True, default=0, null=True)
+ recurring = models.CharField(max_length=1, blank=True)
+ retry_at = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ subscr_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ subscr_effective = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ subscr_id = models.CharField(max_length=19, blank=True)
+ username = models.CharField(max_length=64, blank=True)
+
+ # Dispute Resolution Variables
+ case_creation_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ case_id = models.CharField(max_length=14, blank=True)
+ case_type = models.CharField(max_length=24, blank=True)
+
+ # Variables not categorized
+ receipt_id= models.CharField(max_length=64, blank=True) # 1335-7816-2936-1451
+ currency_code = models.CharField(max_length=32, default="USD", blank=True)
+ handling_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ transaction_subject = models.CharField(max_length=255, blank=True)
- # @@@ Mass Pay Variables (Not Implemented, needs a separate model, for each transaction x)
- # fraud_managment_pending_filters_x = models.CharField(max_length=255, blank=True)
- # option_selection1_x = models.CharField(max_length=200, blank=True)
- # option_selection2_x = models.CharField(max_length=200, blank=True)
- # masspay_txn_id_x = models.CharField(max_length=19, blank=True)
- # mc_currency_x = models.CharField(max_length=32, default="USD", blank=True)
- # mc_fee_x = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- # mc_gross_x = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- # mc_handlingx = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- # payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
- # payment_status = models.CharField(max_length=9, blank=True)
- # reason_code = models.CharField(max_length=15, blank=True)
- # receiver_email_x = models.EmailField(max_length=127, blank=True)
- # status_x = models.CharField(max_length=9, blank=True)
- # unique_id_x = models.CharField(max_length=13, blank=True)
+ # @@@ Mass Pay Variables (Not Implemented, needs a separate model, for each transaction x)
+ # fraud_managment_pending_filters_x = models.CharField(max_length=255, blank=True)
+ # option_selection1_x = models.CharField(max_length=200, blank=True)
+ # option_selection2_x = models.CharField(max_length=200, blank=True)
+ # masspay_txn_id_x = models.CharField(max_length=19, blank=True)
+ # mc_currency_x = models.CharField(max_length=32, default="USD", blank=True)
+ # mc_fee_x = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ # mc_gross_x = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ # mc_handlingx = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ # payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST")
+ # payment_status = models.CharField(max_length=9, blank=True)
+ # reason_code = models.CharField(max_length=15, blank=True)
+ # receiver_email_x = models.EmailField(max_length=127, blank=True)
+ # status_x = models.CharField(max_length=9, blank=True)
+ # unique_id_x = models.CharField(max_length=13, blank=True)
- # Non-PayPal Variables - full IPN/PDT query and time fields.
- ipaddress = models.IPAddressField(blank=True)
- flag = models.BooleanField(default=False, blank=True)
- flag_code = models.CharField(max_length=16, blank=True)
- flag_info = models.TextField(blank=True)
- query = models.TextField(blank=True) # What we sent to PayPal.
- response = models.TextField(blank=True) # What we got back.
- created_at = models.DateTimeField(auto_now_add=True)
- updated_at = models.DateTimeField(auto_now=True)
+ # Non-PayPal Variables - full IPN/PDT query and time fields.
+ ipaddress = models.IPAddressField(blank=True)
+ flag = models.BooleanField(default=False, blank=True)
+ flag_code = models.CharField(max_length=16, blank=True)
+ flag_info = models.TextField(blank=True)
+ query = models.TextField(blank=True) # What we sent to PayPal.
+ response = models.TextField(blank=True) # What we got back.
+ created_at = models.DateTimeField(auto_now_add=True)
+ updated_at = models.DateTimeField(auto_now=True)
- # Where did it come from?
- from_view = models.CharField(max_length=6, null=True, blank=True)
+ # Where did it come from?
+ from_view = models.CharField(max_length=6, null=True, blank=True)
- class Meta:
- abstract = True
+ class Meta:
+ abstract = True
- def __unicode__(self):
- if self.is_transaction():
- return self.format % ("Transaction", self.txn_id)
- else:
- return self.format % ("Recurring", self.recurring_payment_id)
-
- def is_transaction(self):
- return len(self.txn_id) > 0
+ def __unicode__(self):
+ if self.is_transaction():
+ return self.format % ("Transaction", self.txn_id)
+ else:
+ return self.format % ("Recurring", self.recurring_payment_id)
+
+ def is_transaction(self):
+ return len(self.txn_id) > 0
- def is_recurring(self):
- return len(self.recurring_payment_id) > 0
-
- def is_subscription_cancellation(self):
- return self.txn_type == "subscr_cancel"
-
- def is_subscription_end_of_term(self):
- return self.txn_type == "subscr_eot"
-
- def is_subscription_modified(self):
- return self.txn_type == "subscr_modify"
-
- def is_subscription_signup(self):
- return self.txn_type == "subscr_signup"
+ def is_recurring(self):
+ return len(self.recurring_payment_id) > 0
+
+ def is_subscription_cancellation(self):
+ return self.txn_type == "subscr_cancel"
+
+ def is_subscription_end_of_term(self):
+ return self.txn_type == "subscr_eot"
+
+ def is_subscription_modified(self):
+ return self.txn_type == "subscr_modify"
+
+ def is_subscription_signup(self):
+ return self.txn_type == "subscr_signup"
- def is_recurring_create(self):
- return self.txn_type == "recurring_payment_profile_created"
+ def is_recurring_create(self):
+ return self.txn_type == "recurring_payment_profile_created"
- def is_recurring_payment(self):
- return self.txn_type == "recurring_payment"
-
- def is_recurring_cancel(self):
- return self.txn_type == "recurring_payment_profile_cancel"
-
- def is_recurring_skipped(self):
- return self.txn_type == "recurring_payment_skipped"
-
- def is_recurring_failed(self):
- return self.txn_type == "recurring_payment_failed"
-
- def set_flag(self, info, code=None):
- """Sets a flag on the transaction and also sets a reason."""
- self.flag = True
- self.flag_info += info
- if code is not None:
- self.flag_code = code
-
- def verify(self, item_check_callable=None):
- """
- Verifies an IPN and a PDT.
- Checks for obvious signs of weirdness in the payment and flags appropriately.
-
- Provide a callable that takes an instance of this class as a parameter and returns
- a tuple (False, None) if the item is valid. Should return (True, "reason") if the
- item isn't valid. Strange but backward compatible :) This function should check
- that `mc_gross`, `mc_currency` `item_name` and `item_number` are all correct.
+ def is_recurring_payment(self):
+ return self.txn_type == "recurring_payment"
+
+ def is_recurring_cancel(self):
+ return self.txn_type == "recurring_payment_profile_cancel"
+
+ def is_recurring_skipped(self):
+ return self.txn_type == "recurring_payment_skipped"
+
+ def is_recurring_failed(self):
+ return self.txn_type == "recurring_payment_failed"
+
+ def set_flag(self, info, code=None):
+ """Sets a flag on the transaction and also sets a reason."""
+ self.flag = True
+ self.flag_info += info
+ if code is not None:
+ self.flag_code = code
+
+ def verify(self, item_check_callable=None):
+ """
+ Verifies an IPN and a PDT.
+ Checks for obvious signs of weirdness in the payment and flags appropriately.
+
+ Provide a callable that takes an instance of this class as a parameter and returns
+ a tuple (False, None) if the item is valid. Should return (True, "reason") if the
+ item isn't valid. Strange but backward compatible :) This function should check
+ that `mc_gross`, `mc_currency` `item_name` and `item_number` are all correct.
- """
- self.response = self._postback()
- self._verify_postback()
- if not self.flag:
- if self.is_transaction():
- if self.payment_status not in self.PAYMENT_STATUS_CHOICES:
- self.set_flag("Invalid payment_status. (%s)" % self.payment_status)
- if duplicate_txn_id(self):
- self.set_flag("Duplicate txn_id. (%s)" % self.txn_id)
- if self.receiver_email != RECEIVER_EMAIL:
- self.set_flag("Invalid receiver_email. (%s)" % self.receiver_email)
- if callable(item_check_callable):
- flag, reason = item_check_callable(self)
- if flag:
- self.set_flag(reason)
- else:
- # @@@ Run a different series of checks on recurring payments.
- pass
-
- self.save()
- self.send_signals()
+ """
+ self.response = self._postback()
+ self._verify_postback()
+ if not self.flag:
+ if self.is_transaction():
+ if self.payment_status not in self.PAYMENT_STATUS_CHOICES:
+ self.set_flag("Invalid payment_status. (%s)" % self.payment_status)
+ if duplicate_txn_id(self):
+ self.set_flag("Duplicate txn_id. (%s)" % self.txn_id)
+ if self.receiver_email != RECEIVER_EMAIL:
+ self.set_flag("Invalid receiver_email. (%s)" % self.receiver_email)
+ if callable(item_check_callable):
+ flag, reason = item_check_callable(self)
+ if flag:
+ self.set_flag(reason)
+ else:
+ # @@@ Run a different series of checks on recurring payments.
+ pass
+
+ self.save()
+ self.send_signals()
- def verify_secret(self, form_instance, secret):
- """Verifies an IPN payment over SSL using EWP."""
- if not check_secret(form_instance, secret):
- self.set_flag("Invalid secret. (%s)") % secret
- self.save()
- self.send_signals()
+ def verify_secret(self, form_instance, secret):
+ """Verifies an IPN payment over SSL using EWP."""
+ if not check_secret(form_instance, secret):
+ self.set_flag("Invalid secret. (%s)") % secret
+ self.save()
+ self.send_signals()
- def get_endpoint(self):
- """Set Sandbox endpoint if the test variable is present."""
- if self.test_ipn:
- return SANDBOX_POSTBACK_ENDPOINT
- else:
- return POSTBACK_ENDPOINT
+ def get_endpoint(self):
+ """Set Sandbox endpoint if the test variable is present."""
+ if self.test_ipn:
+ return SANDBOX_POSTBACK_ENDPOINT
+ else:
+ return POSTBACK_ENDPOINT
- def send_signals(self):
- """Shout for the world to hear whether a txn was successful."""
+ def send_signals(self):
+ """Shout for the world to hear whether a txn was successful."""
- # Don't do anything if we're not notifying!
- if self.from_view != 'notify':
- return
+ # Don't do anything if we're not notifying!
+ if self.from_view != 'notify':
+ return
- # Transaction signals:
- if self.is_transaction():
- if self.flag:
- payment_was_flagged.send(sender=self)
- else:
- payment_was_successful.send(sender=self)
- # Subscription signals:
- else:
- if self.is_subscription_cancellation():
- subscription_cancel.send(sender=self)
- elif self.is_subscription_signup():
- subscription_signup.send(sender=self)
- elif self.is_subscription_end_of_term():
- subscription_eot.send(sender=self)
- elif self.is_subscription_modified():
- subscription_modify.send(sender=self)
+ # Transaction signals:
+ if self.is_transaction():
+ if self.flag:
+ payment_was_flagged.send(sender=self)
+ else:
+ payment_was_successful.send(sender=self)
+ # Subscription signals:
+ else:
+ if self.is_subscription_cancellation():
+ subscription_cancel.send(sender=self)
+ elif self.is_subscription_signup():
+ subscription_signup.send(sender=self)
+ elif self.is_subscription_end_of_term():
+ subscription_eot.send(sender=self)
+ elif self.is_subscription_modified():
+ subscription_modify.send(sender=self)
- def initialize(self, request):
- """Store the data we'll need to make the postback from the request object."""
- self.query = getattr(request, request.method).urlencode()
- self.ipaddress = request.META.get('REMOTE_ADDR', '')
+ def initialize(self, request):
+ """Store the data we'll need to make the postback from the request object."""
+ self.query = getattr(request, request.method).urlencode()
+ self.ipaddress = request.META.get('REMOTE_ADDR', '')
- def _postback(self):
- """Perform postback to PayPal and store the response in self.response."""
- raise NotImplementedError
-
- def _verify_postback(self):
- """Check self.response is valid andcall self.set_flag if there is an error."""
- raise NotImplementedError
+ def _postback(self):
+ """Perform postback to PayPal and store the response in self.response."""
+ raise NotImplementedError
+
+ def _verify_postback(self):
+ """Check self.response is valid andcall self.set_flag if there is an error."""
+ raise NotImplementedError
diff --git a/paypal/standard/pdt/admin.py b/paypal/standard/pdt/admin.py
index d7f16cb..1890654 100644
--- a/paypal/standard/pdt/admin.py
+++ b/paypal/standard/pdt/admin.py
@@ -7,42 +7,42 @@
# ToDo: How similiar is this to PayPalIPNAdmin? Could we just inherit off one common admin model?
class PayPalPDTAdmin(admin.ModelAdmin):
- date_hierarchy = 'payment_date'
- fieldsets = (
- (None, {
- "fields": L("flag txn_id txn_type payment_status payment_date transaction_entity reason_code pending_reason mc_gross mc_fee auth_status auth_amount auth_exp auth_id")
- }),
- ("Address", {
- "description": "The address of the Buyer.",
- 'classes': ('collapse',),
- "fields": L("address_city address_country address_country_code address_name address_state address_status address_street address_zip")
- }),
- ("Buyer", {
- "description": "The information about the Buyer.",
- 'classes': ('collapse',),
- "fields": L("first_name last_name payer_business_name payer_email payer_id payer_status contact_phone residence_country")
- }),
- ("Seller", {
- "description": "The information about the Seller.",
- 'classes': ('collapse',),
- "fields": L("business item_name item_number quantity receiver_email receiver_id custom invoice memo")
- }),
- ("Subscriber", {
- "description": "The information about the Subscription.",
- 'classes': ('collapse',),
- "fields": L("subscr_id subscr_date subscr_effective")
- }),
- ("Recurring", {
- "description": "Information about recurring Payments.",
- "classes": ("collapse",),
- "fields": L("profile_status initial_payment_amount amount_per_cycle outstanding_balance period_type product_name product_type recurring_payment_id receipt_id next_payment_date")
- }),
- ("Admin", {
- "description": "Additional Info.",
- "classes": ('collapse',),
- "fields": L("test_ipn ipaddress query flag_code flag_info")
- }),
- )
- list_display = L("__unicode__ flag invoice custom payment_status created_at")
- search_fields = L("txn_id recurring_payment_id")
+ date_hierarchy = 'payment_date'
+ fieldsets = (
+ (None, {
+ "fields": L("flag txn_id txn_type payment_status payment_date transaction_entity reason_code pending_reason mc_gross mc_fee auth_status auth_amount auth_exp auth_id")
+ }),
+ ("Address", {
+ "description": "The address of the Buyer.",
+ 'classes': ('collapse',),
+ "fields": L("address_city address_country address_country_code address_name address_state address_status address_street address_zip")
+ }),
+ ("Buyer", {
+ "description": "The information about the Buyer.",
+ 'classes': ('collapse',),
+ "fields": L("first_name last_name payer_business_name payer_email payer_id payer_status contact_phone residence_country")
+ }),
+ ("Seller", {
+ "description": "The information about the Seller.",
+ 'classes': ('collapse',),
+ "fields": L("business item_name item_number quantity receiver_email receiver_id custom invoice memo")
+ }),
+ ("Subscriber", {
+ "description": "The information about the Subscription.",
+ 'classes': ('collapse',),
+ "fields": L("subscr_id subscr_date subscr_effective")
+ }),
+ ("Recurring", {
+ "description": "Information about recurring Payments.",
+ "classes": ("collapse",),
+ "fields": L("profile_status initial_payment_amount amount_per_cycle outstanding_balance period_type product_name product_type recurring_payment_id receipt_id next_payment_date")
+ }),
+ ("Admin", {
+ "description": "Additional Info.",
+ "classes": ('collapse',),
+ "fields": L("test_ipn ipaddress query flag_code flag_info")
+ }),
+ )
+ list_display = L("__unicode__ flag invoice custom payment_status created_at")
+ search_fields = L("txn_id recurring_payment_id")
admin.site.register(PayPalPDT, PayPalPDTAdmin)
\ No newline at end of file
diff --git a/paypal/standard/pdt/forms.py b/paypal/standard/pdt/forms.py
index db6c4da..e86327d 100644
--- a/paypal/standard/pdt/forms.py
+++ b/paypal/standard/pdt/forms.py
@@ -5,5 +5,5 @@
class PayPalPDTForm(PayPalStandardBaseForm):
- class Meta:
- model = PayPalPDT
\ No newline at end of file
+ class Meta:
+ model = PayPalPDT
\ No newline at end of file
diff --git a/paypal/standard/pdt/migrations/0001_first_migration.py b/paypal/standard/pdt/migrations/0001_first_migration.py
index ab7b921..3928968 100644
--- a/paypal/standard/pdt/migrations/0001_first_migration.py
+++ b/paypal/standard/pdt/migrations/0001_first_migration.py
@@ -5,259 +5,259 @@
from paypal.standard.pdt.models import *
class Migration:
-
- def forwards(self, orm):
-
- # Adding model 'PayPalPDT'
- db.create_table('paypal_pdt', (
- ('id', models.AutoField(primary_key=True)),
- ('business', models.CharField(max_length=127, blank=True)),
- ('charset', models.CharField(max_length=32, blank=True)),
- ('custom', models.CharField(max_length=255, blank=True)),
- ('notify_version', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('parent_txn_id', models.CharField("Parent Transaction ID", max_length=19, blank=True)),
- ('receiver_email', models.EmailField(max_length=127, blank=True)),
- ('receiver_id', models.CharField(max_length=127, blank=True)),
- ('residence_country', models.CharField(max_length=2, blank=True)),
- ('test_ipn', models.BooleanField(default=False, blank=True)),
- ('txn_id', models.CharField("Transaction ID", max_length=19, blank=True)),
- ('txn_type', models.CharField("Transaction Type", max_length=128, blank=True)),
- ('verify_sign', models.CharField(max_length=255, blank=True)),
- ('address_country', models.CharField(max_length=64, blank=True)),
- ('address_city', models.CharField(max_length=40, blank=True)),
- ('address_country_code', models.CharField(max_length=64, blank=True)),
- ('address_name', models.CharField(max_length=128, blank=True)),
- ('address_state', models.CharField(max_length=40, blank=True)),
- ('address_status', models.CharField(max_length=11, blank=True)),
- ('address_street', models.CharField(max_length=200, blank=True)),
- ('address_zip', models.CharField(max_length=20, blank=True)),
- ('contact_phone', models.CharField(max_length=20, blank=True)),
- ('first_name', models.CharField(max_length=64, blank=True)),
- ('last_name', models.CharField(max_length=64, blank=True)),
- ('payer_business_name', models.CharField(max_length=127, blank=True)),
- ('payer_email', models.CharField(max_length=127, blank=True)),
- ('payer_id', models.CharField(max_length=13, blank=True)),
- ('auth_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('auth_exp', models.CharField(max_length=28, blank=True)),
- ('auth_id', models.CharField(max_length=19, blank=True)),
- ('auth_status', models.CharField(max_length=9, blank=True)),
- ('exchange_rate', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=16, blank=True)),
- ('invoice', models.CharField(max_length=127, blank=True)),
- ('item_name', models.CharField(max_length=127, blank=True)),
- ('item_number', models.CharField(max_length=127, blank=True)),
- ('mc_currency', models.CharField(default='USD', max_length=32, blank=True)),
- ('mc_fee', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_handling', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('memo', models.CharField(max_length=255, blank=True)),
- ('num_cart_items', models.IntegerField(default=0, null=True, blank=True)),
- ('option_name1', models.CharField(max_length=64, blank=True)),
- ('option_name2', models.CharField(max_length=64, blank=True)),
- ('payer_status', models.CharField(max_length=10, blank=True)),
- ('payment_date', models.DateTimeField(null=True, blank=True)),
- ('payment_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('payment_status', models.CharField(max_length=9, blank=True)),
- ('payment_type', models.CharField(max_length=7, blank=True)),
- ('pending_reason', models.CharField(max_length=14, blank=True)),
- ('protection_eligibility', models.CharField(max_length=32, blank=True)),
- ('quantity', models.IntegerField(default=1, null=True, blank=True)),
- ('reason_code', models.CharField(max_length=15, blank=True)),
- ('remaining_settle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('settle_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('settle_currency', models.CharField(max_length=32, blank=True)),
- ('shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('shipping_method', models.CharField(max_length=255, blank=True)),
- ('tax', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('transaction_entity', models.CharField(max_length=7, blank=True)),
- ('auction_buyer_id', models.CharField(max_length=64, blank=True)),
- ('auction_closing_date', models.DateTimeField(null=True, blank=True)),
- ('auction_multi_item', models.IntegerField(default=0, null=True, blank=True)),
- ('for_auction', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount_per_cycle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('initial_payment_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('next_payment_date', models.DateTimeField(null=True, blank=True)),
- ('outstanding_balance', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('payment_cycle', models.CharField(max_length=32, blank=True)),
- ('period_type', models.CharField(max_length=32, blank=True)),
- ('product_name', models.CharField(max_length=128, blank=True)),
- ('product_type', models.CharField(max_length=128, blank=True)),
- ('profile_status', models.CharField(max_length=32, blank=True)),
- ('recurring_payment_id', models.CharField(max_length=128, blank=True)),
- ('rp_invoice_id', models.CharField(max_length=127, blank=True)),
- ('time_created', models.DateTimeField(null=True, blank=True)),
- ('amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('mc_amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('password', models.CharField(max_length=24, blank=True)),
- ('period1', models.CharField(max_length=32, blank=True)),
- ('period2', models.CharField(max_length=32, blank=True)),
- ('period3', models.CharField(max_length=32, blank=True)),
- ('reattempt', models.CharField(max_length=1, blank=True)),
- ('recur_times', models.IntegerField(default=0, null=True, blank=True)),
- ('recurring', models.CharField(max_length=1, blank=True)),
- ('retry_at', models.DateTimeField(null=True, blank=True)),
- ('subscr_date', models.DateTimeField(null=True, blank=True)),
- ('subscr_effective', models.DateTimeField(null=True, blank=True)),
- ('subscr_id', models.CharField(max_length=19, blank=True)),
- ('username', models.CharField(max_length=64, blank=True)),
- ('case_creation_date', models.DateTimeField(null=True, blank=True)),
- ('case_id', models.CharField(max_length=14, blank=True)),
- ('case_type', models.CharField(max_length=24, blank=True)),
- ('receipt_id', models.CharField(max_length=64, blank=True)),
- ('currency_code', models.CharField(default='USD', max_length=32, blank=True)),
- ('handling_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('transaction_subject', models.CharField(max_length=255, blank=True)),
- ('ipaddress', models.IPAddressField(blank=True)),
- ('flag', models.BooleanField(default=False, blank=True)),
- ('flag_code', models.CharField(max_length=16, blank=True)),
- ('flag_info', models.TextField(blank=True)),
- ('query', models.TextField(blank=True)),
- ('response', models.TextField(blank=True)),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('updated_at', models.DateTimeField(auto_now=True)),
- ('from_view', models.CharField(max_length=6, null=True, blank=True)),
- ('amt', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
- ('cm', models.CharField(max_length=255, blank=True)),
- ('sig', models.CharField(max_length=255, blank=True)),
- ('tx', models.CharField(max_length=255, blank=True)),
- ('st', models.CharField(max_length=32, blank=True)),
- ))
- db.send_create_signal('pdt', ['PayPalPDT'])
-
-
-
- def backwards(self, orm):
-
- # Deleting model 'PayPalPDT'
- db.delete_table('paypal_pdt')
-
-
-
- models = {
- 'pdt.paypalpdt': {
- 'Meta': {'db_table': '"paypal_pdt"'},
- 'address_city': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
- 'address_country': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'address_country_code': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'address_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'address_state': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
- 'address_status': ('models.CharField', [], {'max_length': '11', 'blank': 'True'}),
- 'address_street': ('models.CharField', [], {'max_length': '200', 'blank': 'True'}),
- 'address_zip': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
- 'amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amount_per_cycle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'amt': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'auction_buyer_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'auction_closing_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'auction_multi_item': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
- 'auth_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'auth_exp': ('models.CharField', [], {'max_length': '28', 'blank': 'True'}),
- 'auth_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
- 'auth_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
- 'business': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'case_creation_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'case_id': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
- 'case_type': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
- 'charset': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'cm': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'contact_phone': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
- 'created_at': ('models.DateTimeField', [], {'auto_now_add': 'True'}),
- 'currency_code': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
- 'custom': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'exchange_rate': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16', 'blank': 'True'}),
- 'first_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'flag': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
- 'flag_code': ('models.CharField', [], {'max_length': '16', 'blank': 'True'}),
- 'flag_info': ('models.TextField', [], {'blank': 'True'}),
- 'for_auction': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'from_view': ('models.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
- 'handling_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'id': ('models.AutoField', [], {'primary_key': 'True'}),
- 'initial_payment_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'invoice': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'ipaddress': ('models.IPAddressField', [], {'blank': 'True'}),
- 'item_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'item_number': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'last_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'mc_amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_currency': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
- 'mc_fee': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_handling': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'mc_shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'memo': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'next_payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'notify_version': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'num_cart_items': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
- 'option_name1': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'option_name2': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'outstanding_balance': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'parent_txn_id': ('models.CharField', ['"Parent Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
- 'password': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
- 'payer_business_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'payer_email': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'payer_id': ('models.CharField', [], {'max_length': '13', 'blank': 'True'}),
- 'payer_status': ('models.CharField', [], {'max_length': '10', 'blank': 'True'}),
- 'payment_cycle': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'payment_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'payment_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
- 'payment_type': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
- 'pending_reason': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
- 'period1': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'period2': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'period3': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'period_type': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'product_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'product_type': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'profile_status': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'protection_eligibility': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'quantity': ('models.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}),
- 'query': ('models.TextField', [], {'blank': 'True'}),
- 'reason_code': ('models.CharField', [], {'max_length': '15', 'blank': 'True'}),
- 'reattempt': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
- 'receipt_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'receiver_email': ('models.EmailField', [], {'max_length': '127', 'blank': 'True'}),
- 'receiver_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'recur_times': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
- 'recurring': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
- 'recurring_payment_id': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
- 'remaining_settle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'residence_country': ('models.CharField', [], {'max_length': '2', 'blank': 'True'}),
- 'response': ('models.TextField', [], {'blank': 'True'}),
- 'retry_at': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'rp_invoice_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
- 'settle_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'settle_currency': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'shipping_method': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'sig': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'st': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
- 'subscr_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'subscr_effective': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'subscr_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
- 'tax': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
- 'test_ipn': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
- 'time_created': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
- 'transaction_entity': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
- 'transaction_subject': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'tx': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
- 'txn_id': ('models.CharField', ['"Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
- 'txn_type': ('models.CharField', ['"Transaction Type"'], {'max_length': '128', 'blank': 'True'}),
- 'updated_at': ('models.DateTimeField', [], {'auto_now': 'True'}),
- 'username': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
- 'verify_sign': ('models.CharField', [], {'max_length': '255', 'blank': 'True'})
- }
- }
-
- complete_apps = ['pdt']
+
+ def forwards(self, orm):
+
+ # Adding model 'PayPalPDT'
+ db.create_table('paypal_pdt', (
+ ('id', models.AutoField(primary_key=True)),
+ ('business', models.CharField(max_length=127, blank=True)),
+ ('charset', models.CharField(max_length=32, blank=True)),
+ ('custom', models.CharField(max_length=255, blank=True)),
+ ('notify_version', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('parent_txn_id', models.CharField("Parent Transaction ID", max_length=19, blank=True)),
+ ('receiver_email', models.EmailField(max_length=127, blank=True)),
+ ('receiver_id', models.CharField(max_length=127, blank=True)),
+ ('residence_country', models.CharField(max_length=2, blank=True)),
+ ('test_ipn', models.BooleanField(default=False, blank=True)),
+ ('txn_id', models.CharField("Transaction ID", max_length=19, blank=True)),
+ ('txn_type', models.CharField("Transaction Type", max_length=128, blank=True)),
+ ('verify_sign', models.CharField(max_length=255, blank=True)),
+ ('address_country', models.CharField(max_length=64, blank=True)),
+ ('address_city', models.CharField(max_length=40, blank=True)),
+ ('address_country_code', models.CharField(max_length=64, blank=True)),
+ ('address_name', models.CharField(max_length=128, blank=True)),
+ ('address_state', models.CharField(max_length=40, blank=True)),
+ ('address_status', models.CharField(max_length=11, blank=True)),
+ ('address_street', models.CharField(max_length=200, blank=True)),
+ ('address_zip', models.CharField(max_length=20, blank=True)),
+ ('contact_phone', models.CharField(max_length=20, blank=True)),
+ ('first_name', models.CharField(max_length=64, blank=True)),
+ ('last_name', models.CharField(max_length=64, blank=True)),
+ ('payer_business_name', models.CharField(max_length=127, blank=True)),
+ ('payer_email', models.CharField(max_length=127, blank=True)),
+ ('payer_id', models.CharField(max_length=13, blank=True)),
+ ('auth_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('auth_exp', models.CharField(max_length=28, blank=True)),
+ ('auth_id', models.CharField(max_length=19, blank=True)),
+ ('auth_status', models.CharField(max_length=9, blank=True)),
+ ('exchange_rate', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=16, blank=True)),
+ ('invoice', models.CharField(max_length=127, blank=True)),
+ ('item_name', models.CharField(max_length=127, blank=True)),
+ ('item_number', models.CharField(max_length=127, blank=True)),
+ ('mc_currency', models.CharField(default='USD', max_length=32, blank=True)),
+ ('mc_fee', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_handling', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('memo', models.CharField(max_length=255, blank=True)),
+ ('num_cart_items', models.IntegerField(default=0, null=True, blank=True)),
+ ('option_name1', models.CharField(max_length=64, blank=True)),
+ ('option_name2', models.CharField(max_length=64, blank=True)),
+ ('payer_status', models.CharField(max_length=10, blank=True)),
+ ('payment_date', models.DateTimeField(null=True, blank=True)),
+ ('payment_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('payment_status', models.CharField(max_length=9, blank=True)),
+ ('payment_type', models.CharField(max_length=7, blank=True)),
+ ('pending_reason', models.CharField(max_length=14, blank=True)),
+ ('protection_eligibility', models.CharField(max_length=32, blank=True)),
+ ('quantity', models.IntegerField(default=1, null=True, blank=True)),
+ ('reason_code', models.CharField(max_length=15, blank=True)),
+ ('remaining_settle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('settle_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('settle_currency', models.CharField(max_length=32, blank=True)),
+ ('shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('shipping_method', models.CharField(max_length=255, blank=True)),
+ ('tax', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('transaction_entity', models.CharField(max_length=7, blank=True)),
+ ('auction_buyer_id', models.CharField(max_length=64, blank=True)),
+ ('auction_closing_date', models.DateTimeField(null=True, blank=True)),
+ ('auction_multi_item', models.IntegerField(default=0, null=True, blank=True)),
+ ('for_auction', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount_per_cycle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('initial_payment_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('next_payment_date', models.DateTimeField(null=True, blank=True)),
+ ('outstanding_balance', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('payment_cycle', models.CharField(max_length=32, blank=True)),
+ ('period_type', models.CharField(max_length=32, blank=True)),
+ ('product_name', models.CharField(max_length=128, blank=True)),
+ ('product_type', models.CharField(max_length=128, blank=True)),
+ ('profile_status', models.CharField(max_length=32, blank=True)),
+ ('recurring_payment_id', models.CharField(max_length=128, blank=True)),
+ ('rp_invoice_id', models.CharField(max_length=127, blank=True)),
+ ('time_created', models.DateTimeField(null=True, blank=True)),
+ ('amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('mc_amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('password', models.CharField(max_length=24, blank=True)),
+ ('period1', models.CharField(max_length=32, blank=True)),
+ ('period2', models.CharField(max_length=32, blank=True)),
+ ('period3', models.CharField(max_length=32, blank=True)),
+ ('reattempt', models.CharField(max_length=1, blank=True)),
+ ('recur_times', models.IntegerField(default=0, null=True, blank=True)),
+ ('recurring', models.CharField(max_length=1, blank=True)),
+ ('retry_at', models.DateTimeField(null=True, blank=True)),
+ ('subscr_date', models.DateTimeField(null=True, blank=True)),
+ ('subscr_effective', models.DateTimeField(null=True, blank=True)),
+ ('subscr_id', models.CharField(max_length=19, blank=True)),
+ ('username', models.CharField(max_length=64, blank=True)),
+ ('case_creation_date', models.DateTimeField(null=True, blank=True)),
+ ('case_id', models.CharField(max_length=14, blank=True)),
+ ('case_type', models.CharField(max_length=24, blank=True)),
+ ('receipt_id', models.CharField(max_length=64, blank=True)),
+ ('currency_code', models.CharField(default='USD', max_length=32, blank=True)),
+ ('handling_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('transaction_subject', models.CharField(max_length=255, blank=True)),
+ ('ipaddress', models.IPAddressField(blank=True)),
+ ('flag', models.BooleanField(default=False, blank=True)),
+ ('flag_code', models.CharField(max_length=16, blank=True)),
+ ('flag_info', models.TextField(blank=True)),
+ ('query', models.TextField(blank=True)),
+ ('response', models.TextField(blank=True)),
+ ('created_at', models.DateTimeField(auto_now_add=True)),
+ ('updated_at', models.DateTimeField(auto_now=True)),
+ ('from_view', models.CharField(max_length=6, null=True, blank=True)),
+ ('amt', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)),
+ ('cm', models.CharField(max_length=255, blank=True)),
+ ('sig', models.CharField(max_length=255, blank=True)),
+ ('tx', models.CharField(max_length=255, blank=True)),
+ ('st', models.CharField(max_length=32, blank=True)),
+ ))
+ db.send_create_signal('pdt', ['PayPalPDT'])
+
+
+
+ def backwards(self, orm):
+
+ # Deleting model 'PayPalPDT'
+ db.delete_table('paypal_pdt')
+
+
+
+ models = {
+ 'pdt.paypalpdt': {
+ 'Meta': {'db_table': '"paypal_pdt"'},
+ 'address_city': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
+ 'address_country': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'address_country_code': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'address_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'address_state': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}),
+ 'address_status': ('models.CharField', [], {'max_length': '11', 'blank': 'True'}),
+ 'address_street': ('models.CharField', [], {'max_length': '200', 'blank': 'True'}),
+ 'address_zip': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
+ 'amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amount_per_cycle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'amt': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'auction_buyer_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'auction_closing_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'auction_multi_item': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
+ 'auth_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'auth_exp': ('models.CharField', [], {'max_length': '28', 'blank': 'True'}),
+ 'auth_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
+ 'auth_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
+ 'business': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'case_creation_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'case_id': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
+ 'case_type': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
+ 'charset': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'cm': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'contact_phone': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}),
+ 'created_at': ('models.DateTimeField', [], {'auto_now_add': 'True'}),
+ 'currency_code': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
+ 'custom': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'exchange_rate': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16', 'blank': 'True'}),
+ 'first_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'flag': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'flag_code': ('models.CharField', [], {'max_length': '16', 'blank': 'True'}),
+ 'flag_info': ('models.TextField', [], {'blank': 'True'}),
+ 'for_auction': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'from_view': ('models.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
+ 'handling_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'id': ('models.AutoField', [], {'primary_key': 'True'}),
+ 'initial_payment_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'invoice': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'ipaddress': ('models.IPAddressField', [], {'blank': 'True'}),
+ 'item_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'item_number': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'last_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'mc_amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_currency': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
+ 'mc_fee': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_handling': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'mc_shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'memo': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'next_payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'notify_version': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'num_cart_items': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
+ 'option_name1': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'option_name2': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'outstanding_balance': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'parent_txn_id': ('models.CharField', ['"Parent Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
+ 'password': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}),
+ 'payer_business_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'payer_email': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'payer_id': ('models.CharField', [], {'max_length': '13', 'blank': 'True'}),
+ 'payer_status': ('models.CharField', [], {'max_length': '10', 'blank': 'True'}),
+ 'payment_cycle': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'payment_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'payment_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}),
+ 'payment_type': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
+ 'pending_reason': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}),
+ 'period1': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'period2': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'period3': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'period_type': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'product_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'product_type': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'profile_status': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'protection_eligibility': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'quantity': ('models.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}),
+ 'query': ('models.TextField', [], {'blank': 'True'}),
+ 'reason_code': ('models.CharField', [], {'max_length': '15', 'blank': 'True'}),
+ 'reattempt': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
+ 'receipt_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'receiver_email': ('models.EmailField', [], {'max_length': '127', 'blank': 'True'}),
+ 'receiver_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'recur_times': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
+ 'recurring': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}),
+ 'recurring_payment_id': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}),
+ 'remaining_settle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'residence_country': ('models.CharField', [], {'max_length': '2', 'blank': 'True'}),
+ 'response': ('models.TextField', [], {'blank': 'True'}),
+ 'retry_at': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'rp_invoice_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}),
+ 'settle_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'settle_currency': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'shipping_method': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'sig': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'st': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}),
+ 'subscr_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'subscr_effective': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'subscr_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}),
+ 'tax': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
+ 'test_ipn': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}),
+ 'time_created': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
+ 'transaction_entity': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}),
+ 'transaction_subject': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'tx': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}),
+ 'txn_id': ('models.CharField', ['"Transaction ID"'], {'max_length': '19', 'blank': 'True'}),
+ 'txn_type': ('models.CharField', ['"Transaction Type"'], {'max_length': '128', 'blank': 'True'}),
+ 'updated_at': ('models.DateTimeField', [], {'auto_now': 'True'}),
+ 'username': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}),
+ 'verify_sign': ('models.CharField', [], {'max_length': '255', 'blank': 'True'})
+ }
+ }
+
+ complete_apps = ['pdt']
diff --git a/paypal/standard/pdt/models.py b/paypal/standard/pdt/models.py
index 72e7d7d..d38011c 100644
--- a/paypal/standard/pdt/models.py
+++ b/paypal/standard/pdt/models.py
@@ -14,77 +14,77 @@
# if paypal.standard.pdt is in installed apps
# ... then check for this setting in conf.py
class PayPalSettingsError(Exception):
- """Raised when settings are incorrect."""
+ """Raised when settings are incorrect."""
try:
- IDENTITY_TOKEN = settings.PAYPAL_IDENTITY_TOKEN
+ IDENTITY_TOKEN = settings.PAYPAL_IDENTITY_TOKEN
except:
- raise PayPalSettingsError("You must set PAYPAL_IDENTITY_TOKEN in settings.py. Get this token by enabling PDT in your PayPal account.")
+ raise PayPalSettingsError("You must set PAYPAL_IDENTITY_TOKEN in settings.py. Get this token by enabling PDT in your PayPal account.")
class PayPalPDT(PayPalStandardBase):
- format = u""
+ format = u""
- amt = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
- cm = models.CharField(max_length=255, blank=True)
- sig = models.CharField(max_length=255, blank=True)
- tx = models.CharField(max_length=255, blank=True)
- st = models.CharField(max_length=32, blank=True)
+ amt = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True)
+ cm = models.CharField(max_length=255, blank=True)
+ sig = models.CharField(max_length=255, blank=True)
+ tx = models.CharField(max_length=255, blank=True)
+ st = models.CharField(max_length=32, blank=True)
- class Meta:
- db_table = "paypal_pdt"
- verbose_name = "PayPal PDT"
+ class Meta:
+ db_table = "paypal_pdt"
+ verbose_name = "PayPal PDT"
- def _postback(self):
- """
- Perform PayPal PDT Postback validation.
- Sends the transaction ID and business token to PayPal which responses with
- SUCCESS or FAILED.
-
- """
- postback_dict = dict(cmd="_notify-synch", at=IDENTITY_TOKEN, tx=self.tx)
- postback_params = urlencode(postback_dict)
- return urllib2.urlopen(self.get_endpoint(), postback_params).read()
-
- def get_endpoint(self):
- """Use the sandbox when in DEBUG mode as we don't have a test_ipn variable in pdt."""
- if getattr(settings, 'PAYPAL_DEBUG', settings.DEBUG):
- return SANDBOX_POSTBACK_ENDPOINT
- else:
- return POSTBACK_ENDPOINT
-
- def _verify_postback(self):
- # ### Now we don't really care what result was, just whether a flag was set or not.
- from paypal.standard.pdt.forms import PayPalPDTForm
- result = False
- response_list = self.response.split('\n')
- response_dict = {}
- for i, line in enumerate(response_list):
- unquoted_line = unquote_plus(line).strip()
- if i == 0:
- self.st = unquoted_line
- if self.st == "SUCCESS":
- result = True
- else:
- if self.st != "SUCCESS":
- self.set_flag(line)
- break
- try:
- if not unquoted_line.startswith(' -'):
- k, v = unquoted_line.split('=')
- response_dict[k.strip()] = v.strip()
- except ValueError, e:
- pass
+ def _postback(self):
+ """
+ Perform PayPal PDT Postback validation.
+ Sends the transaction ID and business token to PayPal which responses with
+ SUCCESS or FAILED.
+
+ """
+ postback_dict = dict(cmd="_notify-synch", at=IDENTITY_TOKEN, tx=self.tx)
+ postback_params = urlencode(postback_dict)
+ return urllib2.urlopen(self.get_endpoint(), postback_params).read()
+
+ def get_endpoint(self):
+ """Use the sandbox when in DEBUG mode as we don't have a test_ipn variable in pdt."""
+ if getattr(settings, 'PAYPAL_DEBUG', settings.DEBUG):
+ return SANDBOX_POSTBACK_ENDPOINT
+ else:
+ return POSTBACK_ENDPOINT
+
+ def _verify_postback(self):
+ # ### Now we don't really care what result was, just whether a flag was set or not.
+ from paypal.standard.pdt.forms import PayPalPDTForm
+ result = False
+ response_list = self.response.split('\n')
+ response_dict = {}
+ for i, line in enumerate(response_list):
+ unquoted_line = unquote_plus(line).strip()
+ if i == 0:
+ self.st = unquoted_line
+ if self.st == "SUCCESS":
+ result = True
+ else:
+ if self.st != "SUCCESS":
+ self.set_flag(line)
+ break
+ try:
+ if not unquoted_line.startswith(' -'):
+ k, v = unquoted_line.split('=')
+ response_dict[k.strip()] = v.strip()
+ except ValueError, e:
+ pass
- qd = QueryDict('', mutable=True)
- qd.update(response_dict)
- qd.update(dict(ipaddress=self.ipaddress, st=self.st, flag_info=self.flag_info))
- pdt_form = PayPalPDTForm(qd, instance=self)
- pdt_form.save(commit=False)
-
- def send_signals(self):
- # Send the PDT signals...
- if self.flag:
- pdt_failed.send(sender=self)
- else:
- pdt_successful.send(sender=self)
\ No newline at end of file
+ qd = QueryDict('', mutable=True)
+ qd.update(response_dict)
+ qd.update(dict(ipaddress=self.ipaddress, st=self.st, flag_info=self.flag_info))
+ pdt_form = PayPalPDTForm(qd, instance=self)
+ pdt_form.save(commit=False)
+
+ def send_signals(self):
+ # Send the PDT signals...
+ if self.flag:
+ pdt_failed.send(sender=self)
+ else:
+ pdt_successful.send(sender=self)
\ No newline at end of file
diff --git a/paypal/standard/pdt/tests/test_pdt.py b/paypal/standard/pdt/tests/test_pdt.py
index e49e12b..7bf0ea1 100644
--- a/paypal/standard/pdt/tests/test_pdt.py
+++ b/paypal/standard/pdt/tests/test_pdt.py
@@ -12,108 +12,108 @@
class DummyPayPalPDT(object):
-
- def __init__(self, update_context_dict={}):
- self.context_dict = {'st': 'SUCCESS', 'custom':'cb736658-3aad-4694-956f-d0aeade80194',
- 'txn_id':'1ED550410S3402306', 'mc_gross': '225.00',
- 'business': settings.PAYPAL_RECEIVER_EMAIL, 'error': 'Error code: 1234'}
-
- self.context_dict.update(update_context_dict)
- self.response = ''
-
- def update_with_get_params(self, get_params):
- if get_params.has_key('tx'):
- self.context_dict['txn_id'] = get_params.get('tx')
- if get_params.has_key('amt'):
- self.context_dict['mc_gross'] = get_params.get('amt')
- if get_params.has_key('cm'):
- self.context_dict['custom'] = get_params.get('cm')
-
- def _postback(self, test=True):
- """Perform a Fake PayPal PDT Postback request."""
- # @@@ would be cool if this could live in the test templates dir...
- return render_to_response("pdt/test_pdt_response.html", self.context_dict).content
+
+ def __init__(self, update_context_dict={}):
+ self.context_dict = {'st': 'SUCCESS', 'custom':'cb736658-3aad-4694-956f-d0aeade80194',
+ 'txn_id':'1ED550410S3402306', 'mc_gross': '225.00',
+ 'business': settings.PAYPAL_RECEIVER_EMAIL, 'error': 'Error code: 1234'}
+
+ self.context_dict.update(update_context_dict)
+ self.response = ''
+
+ def update_with_get_params(self, get_params):
+ if get_params.has_key('tx'):
+ self.context_dict['txn_id'] = get_params.get('tx')
+ if get_params.has_key('amt'):
+ self.context_dict['mc_gross'] = get_params.get('amt')
+ if get_params.has_key('cm'):
+ self.context_dict['custom'] = get_params.get('cm')
+
+ def _postback(self, test=True):
+ """Perform a Fake PayPal PDT Postback request."""
+ # @@@ would be cool if this could live in the test templates dir...
+ return render_to_response("pdt/test_pdt_response.html", self.context_dict).content
class PDTTest(TestCase):
- urls = "paypal.standard.pdt.tests.test_urls"
- template_dirs = [os.path.join(os.path.dirname(__file__), 'templates'),]
+ urls = "paypal.standard.pdt.tests.test_urls"
+ template_dirs = [os.path.join(os.path.dirname(__file__), 'templates'),]
- def setUp(self):
- # set up some dummy PDT get parameters
- self.get_params = {"tx":"4WJ86550014687441", "st":"Completed", "amt":"225.00", "cc":"EUR",
- "cm":"a3e192b8-8fea-4a86-b2e8-d5bf502e36be", "item_number":"",
- "sig":"blahblahblah"}
-
- # monkey patch the PayPalPDT._postback function
- self.dpppdt = DummyPayPalPDT()
- self.dpppdt.update_with_get_params(self.get_params)
- PayPalPDT._postback = self.dpppdt._postback
+ def setUp(self):
+ # set up some dummy PDT get parameters
+ self.get_params = {"tx":"4WJ86550014687441", "st":"Completed", "amt":"225.00", "cc":"EUR",
+ "cm":"a3e192b8-8fea-4a86-b2e8-d5bf502e36be", "item_number":"",
+ "sig":"blahblahblah"}
+
+ # monkey patch the PayPalPDT._postback function
+ self.dpppdt = DummyPayPalPDT()
+ self.dpppdt.update_with_get_params(self.get_params)
+ PayPalPDT._postback = self.dpppdt._postback
- def test_verify_postback(self):
- dpppdt = DummyPayPalPDT()
- paypal_response = dpppdt._postback()
- assert('SUCCESS' in paypal_response)
- self.assertEqual(len(PayPalPDT.objects.all()), 0)
- pdt_obj = PayPalPDT()
- pdt_obj.ipaddress = '127.0.0.1'
- pdt_obj.response = paypal_response
- pdt_obj._verify_postback()
- self.assertEqual(len(PayPalPDT.objects.all()), 0)
- self.assertEqual(pdt_obj.txn_id, '1ED550410S3402306')
-
- def test_pdt(self):
- self.assertEqual(len(PayPalPDT.objects.all()), 0)
- self.dpppdt.update_with_get_params(self.get_params)
- paypal_response = self.client.get("/pdt/", self.get_params)
- self.assertContains(paypal_response, 'Transaction complete', status_code=200)
- self.assertEqual(len(PayPalPDT.objects.all()), 1)
+ def test_verify_postback(self):
+ dpppdt = DummyPayPalPDT()
+ paypal_response = dpppdt._postback()
+ assert('SUCCESS' in paypal_response)
+ self.assertEqual(len(PayPalPDT.objects.all()), 0)
+ pdt_obj = PayPalPDT()
+ pdt_obj.ipaddress = '127.0.0.1'
+ pdt_obj.response = paypal_response
+ pdt_obj._verify_postback()
+ self.assertEqual(len(PayPalPDT.objects.all()), 0)
+ self.assertEqual(pdt_obj.txn_id, '1ED550410S3402306')
+
+ def test_pdt(self):
+ self.assertEqual(len(PayPalPDT.objects.all()), 0)
+ self.dpppdt.update_with_get_params(self.get_params)
+ paypal_response = self.client.get("/pdt/", self.get_params)
+ self.assertContains(paypal_response, 'Transaction complete', status_code=200)
+ self.assertEqual(len(PayPalPDT.objects.all()), 1)
- def test_pdt_signals(self):
- self.successful_pdt_fired = False
- self.failed_pdt_fired = False
-
- def successful_pdt(sender, **kwargs):
- self.successful_pdt_fired = True
- pdt_successful.connect(successful_pdt)
-
- def failed_pdt(sender, **kwargs):
- self.failed_pdt_fired = True
- pdt_failed.connect(failed_pdt)
-
- self.assertEqual(len(PayPalPDT.objects.all()), 0)
- paypal_response = self.client.get("/pdt/", self.get_params)
- self.assertContains(paypal_response, 'Transaction complete', status_code=200)
- self.assertEqual(len(PayPalPDT.objects.all()), 1)
- self.assertTrue(self.successful_pdt_fired)
- self.assertFalse(self.failed_pdt_fired)
- pdt_obj = PayPalPDT.objects.all()[0]
- self.assertEqual(pdt_obj.flag, False)
-
- def test_double_pdt_get(self):
- self.assertEqual(len(PayPalPDT.objects.all()), 0)
- paypal_response = self.client.get("/pdt/", self.get_params)
- self.assertContains(paypal_response, 'Transaction complete', status_code=200)
- self.assertEqual(len(PayPalPDT.objects.all()), 1)
- pdt_obj = PayPalPDT.objects.all()[0]
- self.assertEqual(pdt_obj.flag, False)
- paypal_response = self.client.get("/pdt/", self.get_params)
- self.assertContains(paypal_response, 'Transaction complete', status_code=200)
- self.assertEqual(len(PayPalPDT.objects.all()), 1) # we don't create a new pdt
- pdt_obj = PayPalPDT.objects.all()[0]
- self.assertEqual(pdt_obj.flag, False)
+ def test_pdt_signals(self):
+ self.successful_pdt_fired = False
+ self.failed_pdt_fired = False
+
+ def successful_pdt(sender, **kwargs):
+ self.successful_pdt_fired = True
+ pdt_successful.connect(successful_pdt)
+
+ def failed_pdt(sender, **kwargs):
+ self.failed_pdt_fired = True
+ pdt_failed.connect(failed_pdt)
+
+ self.assertEqual(len(PayPalPDT.objects.all()), 0)
+ paypal_response = self.client.get("/pdt/", self.get_params)
+ self.assertContains(paypal_response, 'Transaction complete', status_code=200)
+ self.assertEqual(len(PayPalPDT.objects.all()), 1)
+ self.assertTrue(self.successful_pdt_fired)
+ self.assertFalse(self.failed_pdt_fired)
+ pdt_obj = PayPalPDT.objects.all()[0]
+ self.assertEqual(pdt_obj.flag, False)
+
+ def test_double_pdt_get(self):
+ self.assertEqual(len(PayPalPDT.objects.all()), 0)
+ paypal_response = self.client.get("/pdt/", self.get_params)
+ self.assertContains(paypal_response, 'Transaction complete', status_code=200)
+ self.assertEqual(len(PayPalPDT.objects.all()), 1)
+ pdt_obj = PayPalPDT.objects.all()[0]
+ self.assertEqual(pdt_obj.flag, False)
+ paypal_response = self.client.get("/pdt/", self.get_params)
+ self.assertContains(paypal_response, 'Transaction complete', status_code=200)
+ self.assertEqual(len(PayPalPDT.objects.all()), 1) # we don't create a new pdt
+ pdt_obj = PayPalPDT.objects.all()[0]
+ self.assertEqual(pdt_obj.flag, False)
- def test_no_txn_id_in_pdt(self):
- self.dpppdt.context_dict.pop('txn_id')
- self.get_params={}
- paypal_response = self.client.get("/pdt/", self.get_params)
- self.assertContains(paypal_response, 'Transaction Failed', status_code=200)
- self.assertEqual(len(PayPalPDT.objects.all()), 0)
-
- def test_custom_passthrough(self):
- self.assertEqual(len(PayPalPDT.objects.all()), 0)
- self.dpppdt.update_with_get_params(self.get_params)
- paypal_response = self.client.get("/pdt/", self.get_params)
- self.assertContains(paypal_response, 'Transaction complete', status_code=200)
- self.assertEqual(len(PayPalPDT.objects.all()), 1)
- pdt_obj = PayPalPDT.objects.all()[0]
- self.assertEqual(pdt_obj.custom, self.get_params['cm'] )
\ No newline at end of file
+ def test_no_txn_id_in_pdt(self):
+ self.dpppdt.context_dict.pop('txn_id')
+ self.get_params={}
+ paypal_response = self.client.get("/pdt/", self.get_params)
+ self.assertContains(paypal_response, 'Transaction Failed', status_code=200)
+ self.assertEqual(len(PayPalPDT.objects.all()), 0)
+
+ def test_custom_passthrough(self):
+ self.assertEqual(len(PayPalPDT.objects.all()), 0)
+ self.dpppdt.update_with_get_params(self.get_params)
+ paypal_response = self.client.get("/pdt/", self.get_params)
+ self.assertContains(paypal_response, 'Transaction complete', status_code=200)
+ self.assertEqual(len(PayPalPDT.objects.all()), 1)
+ pdt_obj = PayPalPDT.objects.all()[0]
+ self.assertEqual(pdt_obj.custom, self.get_params['cm'] )
\ No newline at end of file
diff --git a/paypal/standard/pdt/tests/test_urls.py b/paypal/standard/pdt/tests/test_urls.py
index 0eb164c..211f125 100644
--- a/paypal/standard/pdt/tests/test_urls.py
+++ b/paypal/standard/pdt/tests/test_urls.py
@@ -1,5 +1,5 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('paypal.standard.pdt.views',
- (r'^pdt/$', 'pdt'),
+ (r'^pdt/$', 'pdt'),
)
diff --git a/paypal/standard/pdt/urls.py b/paypal/standard/pdt/urls.py
index 9a088ff..e09a907 100644
--- a/paypal/standard/pdt/urls.py
+++ b/paypal/standard/pdt/urls.py
@@ -1,5 +1,5 @@
from django.conf.urls.defaults import *
urlpatterns = patterns('paypal.standard.pdt.views',
- url(r'^$', 'pdt', name="paypal-pdt"),
+ url(r'^$', 'pdt', name="paypal-pdt"),
)
\ No newline at end of file
diff --git a/paypal/standard/pdt/views.py b/paypal/standard/pdt/views.py
index 0993411..e45b269 100644
--- a/paypal/standard/pdt/views.py
+++ b/paypal/standard/pdt/views.py
@@ -9,42 +9,42 @@
@require_GET
def pdt(request, item_check_callable=None, template="pdt/pdt.html", context=None):
- """Payment data transfer implementation: http://tinyurl.com/c9jjmw"""
- context = context or {}
- pdt_obj = None
- txn_id = request.GET.get('tx')
- failed = False
- if txn_id is not None:
- # If an existing transaction with the id tx exists: use it
- try:
- pdt_obj = PayPalPDT.objects.get(txn_id=txn_id)
- except PayPalPDT.DoesNotExist:
- # This is a new transaction so we continue processing PDT request
- pass
-
- if pdt_obj is None:
- form = PayPalPDTForm(request.GET)
- if form.is_valid():
- try:
- pdt_obj = form.save(commit=False)
- except Exception, e:
- error = repr(e)
- failed = True
- else:
- error = form.errors
- failed = True
-
- if failed:
- pdt_obj = PayPalPDT()
- pdt_obj.set_flag("Invalid form. %s" % error)
-
- pdt_obj.initialize(request)
-
- if not failed:
- # The PDT object gets saved during verify
- pdt_obj.verify(item_check_callable)
- else:
- pass # we ignore any PDT requests that don't have a transaction id
+ """Payment data transfer implementation: http://tinyurl.com/c9jjmw"""
+ context = context or {}
+ pdt_obj = None
+ txn_id = request.GET.get('tx')
+ failed = False
+ if txn_id is not None:
+ # If an existing transaction with the id tx exists: use it
+ try:
+ pdt_obj = PayPalPDT.objects.get(txn_id=txn_id)
+ except PayPalPDT.DoesNotExist:
+ # This is a new transaction so we continue processing PDT request
+ pass
+
+ if pdt_obj is None:
+ form = PayPalPDTForm(request.GET)
+ if form.is_valid():
+ try:
+ pdt_obj = form.save(commit=False)
+ except Exception, e:
+ error = repr(e)
+ failed = True
+ else:
+ error = form.errors
+ failed = True
+
+ if failed:
+ pdt_obj = PayPalPDT()
+ pdt_obj.set_flag("Invalid form. %s" % error)
+
+ pdt_obj.initialize(request)
+
+ if not failed:
+ # The PDT object gets saved during verify
+ pdt_obj.verify(item_check_callable)
+ else:
+ pass # we ignore any PDT requests that don't have a transaction id
- context.update({"failed":failed, "pdt_obj":pdt_obj})
- return render_to_response(template, context, RequestContext(request))
\ No newline at end of file
+ context.update({"failed":failed, "pdt_obj":pdt_obj})
+ return render_to_response(template, context, RequestContext(request))
\ No newline at end of file
diff --git a/paypal/standard/widgets.py b/paypal/standard/widgets.py
index 51aea94..408e470 100644
--- a/paypal/standard/widgets.py
+++ b/paypal/standard/widgets.py
@@ -7,25 +7,25 @@
class ValueHiddenInput(forms.HiddenInput):
- """
- Widget that renders only if it has a value.
- Used to remove unused fields from PayPal buttons.
- """
- def render(self, name, value, attrs=None):
- if value is None:
- return u''
- else:
- return super(ValueHiddenInput, self).render(name, value, attrs)
+ """
+ Widget that renders only if it has a value.
+ Used to remove unused fields from PayPal buttons.
+ """
+ def render(self, name, value, attrs=None):
+ if value is None:
+ return u''
+ else:
+ return super(ValueHiddenInput, self).render(name, value, attrs)
class ReservedValueHiddenInput(ValueHiddenInput):
- """
- Overrides the default name attribute of the form.
- Used for the PayPal `return` field.
- """
- def render(self, name, value, attrs=None):
- if value is None:
- value = ''
- final_attrs = self.build_attrs(attrs, type=self.input_type)
- if value != '':
- final_attrs['value'] = force_unicode(value)
- return mark_safe(u'' % flatatt(final_attrs))
\ No newline at end of file
+ """
+ Overrides the default name attribute of the form.
+ Used for the PayPal `return` field.
+ """
+ def render(self, name, value, attrs=None):
+ if value is None:
+ value = ''
+ final_attrs = self.build_attrs(attrs, type=self.input_type)
+ if value != '':
+ final_attrs['value'] = force_unicode(value)
+ return mark_safe(u'' % flatatt(final_attrs))
\ No newline at end of file
diff --git a/runtests.py b/runtests.py
index dfe14e7..290d3de 100644
--- a/runtests.py
+++ b/runtests.py
@@ -7,34 +7,34 @@
from django.conf import settings
if not settings.configured:
- settings.configure(
- ROOT_URLCONF='',
- DATABASE_ENGINE='sqlite3',
- PAYPAL_RECEIVER_EMAIL='test@example.com',
- PAYPAL_TEST=True,
- # Please dont make me create another test account and remove this from here :)
- PAYPAL_WPP_USER='dcrame_1278645792_biz_api1.gmail.com',
- PAYPAL_WPP_PASSWORD='1278645801',
- PAYPAL_WPP_SIGNATURE='A4k1.O6xTyld5TiKeVmCuOgqzLRuAKuTtSG.7BD3R9E8SBa-J0pbUeYp',
- INSTALLED_APPS=[
- 'paypal.pro',
- 'paypal.standard',
- 'paypal.standard.ipn',
- # 'paypal.standard.pdt', # we need the PDT token
- ]
- )
+ settings.configure(
+ ROOT_URLCONF='',
+ DATABASE_ENGINE='sqlite3',
+ PAYPAL_RECEIVER_EMAIL='test@example.com',
+ PAYPAL_TEST=True,
+ # Please dont make me create another test account and remove this from here :)
+ PAYPAL_WPP_USER='dcrame_1278645792_biz_api1.gmail.com',
+ PAYPAL_WPP_PASSWORD='1278645801',
+ PAYPAL_WPP_SIGNATURE='A4k1.O6xTyld5TiKeVmCuOgqzLRuAKuTtSG.7BD3R9E8SBa-J0pbUeYp',
+ INSTALLED_APPS=[
+ 'paypal.pro',
+ 'paypal.standard',
+ 'paypal.standard.ipn',
+ # 'paypal.standard.pdt', # we need the PDT token
+ ]
+ )
from django.test.simple import run_tests
def runtests(*test_args):
- if not test_args:
- test_args = ['pro', 'standard', 'ipn']
- parent = dirname(abspath(__file__))
- sys.path.insert(0, parent)
- failures = run_tests(test_args, verbosity=1, interactive=True)
- sys.exit(failures)
+ if not test_args:
+ test_args = ['pro', 'standard', 'ipn']
+ parent = dirname(abspath(__file__))
+ sys.path.insert(0, parent)
+ failures = run_tests(test_args, verbosity=1, interactive=True)
+ sys.exit(failures)
if __name__ == '__main__':
- runtests(*sys.argv[1:])
\ No newline at end of file
+ runtests(*sys.argv[1:])
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 9988721..c84a599 100644
--- a/setup.py
+++ b/setup.py
@@ -5,24 +5,24 @@
import paypal
setup(
- name='django-paypal',
- version=".".join(map(str, paypal.__version__)),
- author='John Boxall',
- author_email='john@handimobility.ca',
- maintainer="David Cramer",
- maintainer_email="dcramer@gmail.com",
- url='http://github.com/johnboxall/django-paypal',
- install_requires=[
- 'Django>=1.0'
- ],
- description = 'A pluggable Django application for integrating PayPal Payments Standard or Payments Pro',
- packages=find_packages(),
- include_package_data=True,
- classifiers=[
- "Framework :: Django",
- "Intended Audience :: Developers",
- "Intended Audience :: System Administrators",
- "Operating System :: OS Independent",
- "Topic :: Software Development"
- ],
+ name='django-paypal',
+ version=".".join(map(str, paypal.__version__)),
+ author='John Boxall',
+ author_email='john@handimobility.ca',
+ maintainer="David Cramer",
+ maintainer_email="dcramer@gmail.com",
+ url='http://github.com/johnboxall/django-paypal',
+ install_requires=[
+ 'Django>=1.0'
+ ],
+ description = 'A pluggable Django application for integrating PayPal Payments Standard or Payments Pro',
+ packages=find_packages(),
+ include_package_data=True,
+ classifiers=[
+ "Framework :: Django",
+ "Intended Audience :: Developers",
+ "Intended Audience :: System Administrators",
+ "Operating System :: OS Independent",
+ "Topic :: Software Development"
+ ],
)