De-vendorizing paypal.

This commit is contained in:
Samuel Clay 2020-11-12 17:38:09 -05:00
parent 21749b64a8
commit c91fbf0b32
65 changed files with 6 additions and 5199 deletions

View file

@ -28,9 +28,9 @@ from utils import json_functions as json
from utils.user_functions import generate_secret_token
from utils.feed_functions import chunks
from vendor.timezones.fields import TimeZoneField
from vendor.paypal.standard.ipn.signals import subscription_signup, payment_was_successful, recurring_payment
from vendor.paypal.standard.ipn.signals import payment_was_flagged
from vendor.paypal.standard.ipn.models import PayPalIPN
from paypal.standard.ipn.signals import subscription_signup, payment_was_successful, recurring_payment
from paypal.standard.ipn.signals import payment_was_flagged
from paypal.standard.ipn.models import PayPalIPN
from vendor.paypalapi.interface import PayPalInterface
from vendor.paypalapi.exceptions import PayPalAPIResponseError
from zebra.signals import zebra_webhook_customer_subscription_created

View file

@ -31,7 +31,7 @@ from utils.view_functions import render_to, is_true
from utils.user_functions import get_user
from utils import log as logging
from vendor.paypalapi.exceptions import PayPalAPIResponseError
from vendor.paypal.standard.forms import PayPalPaymentsForm
from paypal.standard.forms import PayPalPaymentsForm
SINGLE_FIELD_PREFS = ('timezone','feed_pane_size','hide_mobile','send_emails',
'hide_getting_started', 'has_setup_feeds', 'has_found_friends',

View file

@ -12,6 +12,7 @@ django-cors-middleware==1.3.1
django-extensions==1.6.7
django-mailgun==0.9.1
django-oauth-toolkit==0.7.2
django-paypal==0.5.0
django-qurl==0.1.1
django-redis-cache==1.5.5
django-redis-sessions==0.6.1

View file

@ -328,7 +328,7 @@ INSTALLED_APPS = (
'django_extensions',
'djcelery',
# 'kombu.transport.django',
'vendor.paypal.standard.ipn',
'paypal.standard.ipn',
'apps.rss_feeds',
'apps.reader',
'apps.analyzer',

View file

@ -1,354 +0,0 @@
Django PayPal
=============
About
-----
Django PayPal is a pluggable application that implements with PayPal Payments
Standard and Payments Pro.
Before diving in, a quick review of PayPal's payment methods is in order! [PayPal Payments Standard](https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_WebsitePaymentsStandard_IntegrationGuide.pdf) is the "Buy it Now" buttons you may have
seen floating around the internets. Buyers click on the button and are taken to PayPal's website where they can pay for the product. After completing the purchase PayPal makes an HTTP POST to your `notify_url`. PayPal calls this process [Instant Payment Notification](https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_OrderMgmt_IntegrationGuide.pdf) (IPN) but you may know it as [webhooks](http://blog.webhooks.org). This method kinda sucks because it drops your customers off at PayPal's website but it's easy to implement and doesn't require SSL.
PayPal Payments Pro allows you to accept payments on your website. It contains two distinct payment flows - Direct Payment allows the user to enter credit card information on your website and pay on your website. Express Checkout sends the user over to PayPal to confirm their payment method before redirecting back to your website for confirmation. PayPal rules state that both methods must be implemented.
There is currently an active discussion over the handling of some of the finer points of the PayPal API and the evolution of this code base - check it out over at [Django PayPal on Google Groups](http://groups.google.com/group/django-paypal).
Using PayPal Payments Standard IPN:
-------------------------------
1. Download the code from GitHub:
git clone git://github.com/johnboxall/django-paypal.git paypal
1. Edit `settings.py` and add `paypal.standard.ipn` to your `INSTALLED_APPS`
and `PAYPAL_RECEIVER_EMAIL`:
# settings.py
...
INSTALLED_APPS = (... 'paypal.standard.ipn', ...)
...
PAYPAL_RECEIVER_EMAIL = "yourpaypalemail@example.com"
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
write out the HTML.
# views.py
...
from vendor.paypal.standard.forms import PayPalPaymentsForm
def view_that_asks_for_money(request):
# What you want the button to do.
paypal_dict = {
"business": "yourpaypalemail@example.com",
"amount": "10000000.00",
"item_name": "name of the item",
"invoice": "unique-invoice-id",
"notify_url": "http://www.example.com/your-ipn-location/",
"return_url": "http://www.example.com/your-return-location/",
"cancel_return": "http://www.example.com/your-cancel-location/",
}
# Create the instance.
form = PayPalPaymentsForm(initial=paypal_dict)
context = {"form": form}
return render_to_response("payment.html", context)
<!-- payment.html -->
...
<h1>Show me the money!</h1>
<!-- writes out the form tag automatically -->
{{ form.render }}
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).
The view `paypal.standard.ipn.views.ipn` handles IPN processing. To set the
correct `notify_url` add the following to your `urls.py`:
# urls.py
...
urlpatterns = patterns('',
(r'^something/hard/to/guess/', include('paypal.standard.ipn.urls')),
)
1. Whenever an IPN is processed a signal will be sent with the result of the
transaction. Connect the signals to actions to perform the needed operations
when a successful payment is recieved.
There are two signals for basic transactions:
- `payment_was_succesful`
- `payment_was_flagged`
And four signals for subscriptions:
- `subscription_cancel` - Sent when a subscription is cancelled.
- `subscription_eot` - Sent when a subscription expires.
- `subscription_modify` - Sent when a subscription is modified.
- `subscription_signup` - Sent when a subscription is created.
Connect to these signals and update your data accordingly. [Django Signals Documentation](http://docs.djangoproject.com/en/dev/topics/signals/).
# models.py
...
from vendor.paypal.standard.ipn.signals import payment_was_successful
def show_me_the_money(sender, **kwargs):
ipn_obj = sender
# Undertake some action depending upon `ipn_obj`.
if ipn_obj.custom == "Upgrade all users!":
Users.objects.update(paid=True)
payment_was_successful.connect(show_me_the_money)
Using PayPal Payments Standard PDT:
-------------------------------
Paypal Payment Data Transfer (PDT) allows you to display transaction details to a customer immediately on return to your site unlike PayPal IPN which may take some seconds. [You will need to enable PDT in your PayPal account to use it.your PayPal account to use it](https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/howto_html_paymentdatatransfer).
1. Download the code from GitHub:
git clone git://github.com/johnboxall/django-paypal.git paypal
1. Edit `settings.py` and add `paypal.standard.pdt` to your `INSTALLED_APPS`. Also set `PAYPAL_IDENTITY_TOKEN` - you can find the correct value of this setting from the PayPal website:
# settings.py
...
INSTALLED_APPS = (... 'paypal.standard.pdt', ...)
PAYPAL_IDENTITY_TOKEN = "xxx"
1. Create a view that uses `PayPalPaymentsForm` just like in PayPal IPN.
1. After someone uses this button to buy something PayPal will return the user to your site at
your "return_url" with some extra GET parameters. PayPal calls this Payment Data Transfer (PDT).
The view `paypal.standard.pdt.views.pdt` handles PDT processing. to specify the correct
`return_url` add the following to your `urls.py`:
# urls.py
...
urlpatterns = patterns('',
(r'^paypal/pdt/', include('paypal.standard.pdt.urls')),
...
)
Using PayPal Payments Standard with Subscriptions:
-------------------------------
1. For subscription actions, you'll need to add a parameter to tell it to use the subscription buttons and the command, plus any
subscription-specific settings:
# views.py
...
paypal_dict = {
"cmd": "_xclick-subscriptions",
"business": "your_account@paypal",
"a3": "9.99", # monthly price
"p3": 1, # duration of each unit (depends on unit)
"t3": "M", # duration unit ("M for Month")
"src": "1", # make payments recur
"sra": "1", # reattempt payment on payment error
"no_note": "1", # remove extra notes (optional)
"item_name": "my cool subscription",
"notify_url": "http://www.example.com/your-ipn-location/",
"return_url": "http://www.example.com/your-return-location/",
"cancel_return": "http://www.example.com/your-cancel-location/",
}
# Create the instance.
form = PayPalPaymentsForm(initial=paypal_dict, button_type="subscribe")
# Output the button.
form.render()
Using PayPal Payments Standard with Encrypted Buttons:
------------------------------------------------------
Use this method to encrypt your button so sneaky gits don't try to hack it. Thanks to [Jon Atkinson](http://jonatkinson.co.uk/) for the [tutorial](http://jonatkinson.co.uk/paypal-encrypted-buttons-django/).
1. Encrypted buttons require the `M2Crypto` library:
easy_install M2Crypto
1. Encrypted buttons require certificates. Create a private key:
openssl genrsa -out paypal.pem 1024
1. Create a public key:
openssl req -new -key paypal.pem -x509 -days 365 -out pubpaypal.pem
1. Upload your public key to the paypal website (sandbox or live).
[https://www.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert](https://www.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert)
[https://www.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert](https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert)
1. Copy your `cert id` - you'll need it in two steps. It's on the screen where
you uploaded your public key.
1. Download PayPal's public certificate - it's also on that screen.
1. Edit your `settings.py` to include cert information:
# settings.py
PAYPAL_PRIVATE_CERT = '/path/to/paypal.pem'
PAYPAL_PUBLIC_CERT = '/path/to/pubpaypal.pem'
PAYPAL_CERT = '/path/to/paypal_cert.pem'
PAYPAL_CERT_ID = 'get-from-paypal-website'
1. Swap out your unencrypted button for a `PayPalEncryptedPaymentsForm`:
# views.py
from vendor.paypal.standard.forms import PayPalEncryptedPaymentsForm
def view_that_asks_for_money(request):
...
# Create the instance.
form = PayPalPaymentsForm(initial=paypal_dict)
# Works just like before!
form.render()
Using PayPal Payments Standard with Encrypted Buttons and Shared Secrets:
-------------------------------------------------------------------------
This method uses Shared secrets instead of IPN postback to verify that transactions
are legit. PayPal recommends you should use Shared Secrets if:
* You are not using a shared website hosting service.
* You have enabled SSL on your web server.
* You are using Encrypted Website Payments.
* You use the notify_url variable on each individual payment transaction.
Use postbacks for validation if:
* You rely on a shared website hosting service
* You do not have SSL enabled on your web server
1. Swap out your button for a `PayPalSharedSecretEncryptedPaymentsForm`:
# views.py
from vendor.paypal.standard.forms import PayPalSharedSecretEncryptedPaymentsForm
def view_that_asks_for_money(request):
...
# Create the instance.
form = PayPalSharedSecretEncryptedPaymentsForm(initial=paypal_dict)
# Works just like before!
form.render()
1. Verify that your IPN endpoint is running on SSL - `request.is_secure()` should return `True`!
Using PayPal Payments Pro (WPP)
-------------------------------
WPP is the more awesome version of PayPal that lets you accept payments on your
site. WPP reuses code from `paypal.standard` so you'll need to include both
apps. [There is an explanation of WPP in the PayPal Forums](http://www.pdncommunity.com/pdn/board/message?board.id=wppro&thread.id=192).
1. Edit `settings.py` and add `paypal.standard` and `paypal.pro` to your
`INSTALLED_APPS`, also set your PayPal settings:
# settings.py
...
INSTALLED_APPS = (... 'paypal.standard', 'paypal.pro', ...)
PAYPAL_TEST = True # Testing mode on
PAYPAL_WPP_USER = "???" # Get from vendor.paypal
PAYPAL_WPP_PASSWORD = "???"
PAYPAL_WPP_SIGNATURE = "???"
1. Run `python manage.py syncdb` to add the required tables.
1. Write a wrapper view for `paypal.pro.views.PayPalPro`:
# views.py
from vendor.paypal.pro.views import PayPalPro
def buy_my_item(request):
item = {"amt": "10.00", # amount to charge for item
"inv": "inventory", # unique tracking variable paypal
"custom": "tracking", # custom tracking variable for you
"cancelurl": "http://...", # Express checkout cancel url
"returnurl": "http://..."} # Express checkout return url
kw = {"item": item, # what you're selling
"payment_template": "payment.html", # template name for payment
"confirm_template": "confirmation.html", # template name for confirmation
"success_url": "/success/"} # redirect location after success
ppp = PayPalPro(**kw)
return ppp(request)
1. Create templates for payment and confirmation. By default both templates are
populated with the context variable `form` which contains either a
`PaymentForm` or a `Confirmation` form.
<!-- payment.html -->
<h1>Show me the money</h1>
<form method="post" action="">
{{ form }}
<input type="submit" value="Pay Up">
</form>
<!-- confirmation.html -->
<h1>Are you sure you want to buy this thing?</h1>
<form method="post" action="">
{{ form }}
<input type="submit" value="Yes I Yams">
</form>
1. Add your view to `urls.py`, and add the IPN endpoint to receive callbacks
from vendor.paypal:
# urls.py
...
urlpatterns = ('',
...
(r'^payment-url/$', 'myproject.views.buy_my_item')
(r'^some/obscure/name/', include('paypal.standard.ipn.urls')),
)
1. Profit.
Links:
------
1. [Set your IPN Endpoint on the PayPal Sandbox](https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_profile-ipn-notify)
2. [Django PayPal on Google Groups](http://groups.google.com/group/django-paypal)
License (MIT)
=============
Copyright (c) 2009 Handi Mobility Inc.
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

View file

@ -1,2 +0,0 @@
VERSION = (0, 1, 4, 'a', 0)
__version__ = ".".join(map(str, VERSION[0:3])) + "".join(map(str, VERSION[3:]))

View file

View file

@ -1,13 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.contrib import admin
from paypal.pro.models import PayPalNVP
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')
admin.site.register(PayPalNVP, PayPalNVPAdmin)

View file

@ -1,71 +0,0 @@
#!/usr/bin/env python
# -*- 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
"""
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}$"),
}
# Well known test numbers
TEST_NUMBERS = [
"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()
class CreditCard(object):
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_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 get_type(self):
"""Return the type if it matches one of the cards."""
for card, pattern in CARDS.items():
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

View file

@ -1 +0,0 @@
class PayPalFailure(Exception): pass

View file

@ -1,347 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from calendar import monthrange
from datetime import date
from django import forms
from django.utils.translation import ugettext as _
from six.moves import range
from paypal.pro.creditcard import verify_credit_card
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
# 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]
def format_output(self, rendered_widgets):
html = u' / '.join(rendered_widgets)
return u'<span style="white-space: nowrap">%s</span>' % html
class CreditCardExpiryField(forms.MultiValueField):
EXP_MONTH = [(x, x) for x in range(1, 13)]
EXP_YEAR = [(x, x) for x in range(date.today().year, date.today().year + 15)]
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 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
class CreditCardCVV2Field(forms.CharField):
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')),
)
class CountryField(forms.ChoiceField):
def __init__(self, *args, **kwargs):
kwargs.setdefault('choices', COUNTRIES)
super(CountryField, self).__init__(*args, **kwargs)

View file

@ -1,49 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django import forms
from paypal.pro.fields import CreditCardField, CreditCardExpiryField, CreditCardCVV2Field, CountryField
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")
currencycode = forms.CharField(widget=forms.HiddenInput(), initial="USD")
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
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())

View file

@ -1,331 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import datetime
import logging
import pprint
import time
from django.conf import settings
from django.forms.models import fields_for_model
from django.http import QueryDict
from django.utils.functional import cached_property
from django.utils.http import urlencode
from six.moves.urllib.request import urlopen
from paypal.pro.signals import payment_was_successful, recurring_cancel, recurring_suspend, recurring_reactivate, payment_profile_created
from paypal.pro.models import PayPalNVP
from paypal.pro.exceptions import PayPalFailure
USER = settings.PAYPAL_WPP_USER
PASSWORD = settings.PAYPAL_WPP_PASSWORD
SIGNATURE = settings.PAYPAL_WPP_SIGNATURE
VERSION = 116.0
BASE_PARAMS = dict(USER=USER, PWD=PASSWORD, SIGNATURE=SIGNATURE, VERSION=VERSION)
ENDPOINT = "https://api-3t.paypal.com/nvp"
SANDBOX_ENDPOINT = "https://api-3t.sandbox.paypal.com/nvp"
log = logging.getLogger(__file__)
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)
def paypaltime2datetime(s):
"""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."""
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 getattr(settings, 'PAYPAL_TEST', True):
self.endpoint = SANDBOX_ENDPOINT
else:
self.endpoint = ENDPOINT
self.signature_values = params
self.signature = urlencode(self.signature_values) + "&"
@cached_property
def NVP_FIELDS(self):
# Put this onto class and load lazily, because in some cases there is an
# import order problem if we put it at module level.
return list(fields_for_model(PayPalNVP).keys())
def doDirectPayment(self, params):
"""Call PayPal DoDirectPayment method."""
defaults = {"method": "DoDirectPayment", "paymentaction": "Sale"}
required = ["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(sender=nvp_obj, **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 "amt" in params:
import warnings
warnings.warn("'amt' has been deprecated. 'paymentrequest_0_amt' "
"should be used instead.", DeprecationWarning)
# Make a copy so we don't change things unexpectedly
params = params.copy()
params.update({'paymentrequest_0_amt': params['amt']})
del params['amt']
if self._is_recurring(params):
params = self._recurring_setExpressCheckout_adapter(params)
defaults = {"method": "SetExpressCheckout", "noshipping": 1}
required = ["returnurl", "cancelurl", "paymentrequest_0_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:
"""
if "amt" in params:
import warnings
warnings.warn("'amt' has been deprecated. 'paymentrequest_0_amt' "
"should be used instead.", DeprecationWarning)
# Make a copy so we don't change things unexpectedly
params = params.copy()
params.update({'paymentrequest_0_amt': params['amt']})
del params['amt']
defaults = {"method": "DoExpressCheckoutPayment", "paymentaction": "Sale"}
required = ["returnurl", "cancelurl", "paymentrequest_0_amt", "token", "payerid"]
nvp_obj = self._fetch(params, required, defaults)
if nvp_obj.flag:
raise PayPalFailure(nvp_obj.flag_info)
payment_was_successful.send(sender=nvp_obj, **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 = ["profilestartdate", "billingperiod", "billingfrequency", "amt"]
# Direct payments require CC data
if direct:
required + ["creditcardtype", "acct", "expdate", "firstname", "lastname"]
else:
required + ["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(sender=nvp_obj, **params)
return nvp_obj
def getExpressCheckoutDetails(self, params):
defaults = {"method": "GetExpressCheckoutDetails"}
required = ["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 createBillingAgreement(self, params):
"""
Create a billing agreement for future use, without any initial payment
"""
defaults = {"method": "CreateBillingAgreement"}
required = ["token"]
nvp_obj = self._fetch(params, required, defaults)
if nvp_obj.flag:
raise PayPalFailure(nvp_obj.flag_info)
return nvp_obj
def getTransactionDetails(self, params):
defaults = {"method": "GetTransactionDetails"}
required = ["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 = ["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 = ["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 doReferenceTransaction(self, params):
"""
Process a payment from a buyer's account, identified by a previous
transaction.
The `paymentaction` param defaults to "Sale", but may also contain the
values "Authorization" or "Order".
"""
defaults = {"method": "DoReferenceTransaction",
"paymentaction": "Sale"}
required = ["referenceid", "amt"]
nvp_obj = self._fetch(params, required, defaults)
if nvp_obj.flag:
raise PayPalFailure(nvp_obj.flag_info)
return nvp_obj
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 = ["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):
log.debug('PayPal Request:\n%s\n', pprint.pformat(defaults))
log.debug('PayPal Response:\n%s\n', pprint.pformat(response_params))
# Gather all NVP parameters to pass to a new instance.
nvp_params = {}
tmpd = defaults.copy()
tmpd.update(response_params)
for k, v in tmpd.items():
if k in self.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 urlopen(self.endpoint, data.encode("ascii")).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.items()))
def _parse_response(self, response):
"""Turn the PayPal response into a dict"""
q = QueryDict(response, encoding='UTF-8').dict()
return {k.lower(): v for k,v in q.items()}

View file

@ -1,53 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='PayPalNVP',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('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(null=True, blank=True)),
('profileid', models.CharField(max_length=32, blank=True)),
('profilereference', models.CharField(max_length=128, blank=True)),
('correlationid', models.CharField(max_length=32, blank=True)),
('token', models.CharField(max_length=64, blank=True)),
('payerid', models.CharField(max_length=64, blank=True)),
('firstname', models.CharField(max_length=255, verbose_name=b'First Name', blank=True)),
('lastname', models.CharField(max_length=255, verbose_name=b'Last Name', blank=True)),
('street', models.CharField(max_length=255, verbose_name=b'Street Address', blank=True)),
('city', models.CharField(max_length=255, verbose_name=b'City', blank=True)),
('state', models.CharField(max_length=255, verbose_name=b'State', blank=True)),
('countrycode', models.CharField(max_length=2, verbose_name=b'Country', blank=True)),
('zip', models.CharField(max_length=32, verbose_name=b'Postal / Zip Code', blank=True)),
('invnum', models.CharField(max_length=255, blank=True)),
('custom', models.CharField(max_length=255, blank=True)),
('flag', models.BooleanField(default=False)),
('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)),
('user', models.ForeignKey(blank=True, to=settings.AUTH_USER_MODEL, null=True)),
],
options={
'db_table': 'paypal_nvp',
'verbose_name': 'PayPal NVP',
},
bases=(models.Model,),
),
]

View file

@ -1,132 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.conf import settings
from django.db import models
from django.utils.http import urlencode
from django.forms.models import model_to_dict
try:
from idmapper.models import SharedMemoryModel as Model
except ImportError:
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 = ["expdate",
"cvv2",
"acct",
]
ADMIN_FIELDS = ['id',
'user',
'flag',
'flag_code',
'flag_info',
'query',
'response',
'created_at',
'updated_at',
]
ITEM_FIELDS = ["amt",
"custom",
"invnum",
]
DIRECT_FIELDS = ["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(getattr(settings, 'AUTH_USER_MODEL', 'auth.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."""
if request is not None:
self.ipaddress = request.META.get('REMOTE_ADDR', '').split(':')[0]
if hasattr(request, "user") and request.user.is_authenticated():
self.user = request.user
else:
self.ipaddress = ''
# No storing credit card info.
query_data = dict((k, v) for k, v in paypal_request.items() 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', ''))
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)
# 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)

View file

@ -1,25 +0,0 @@
from django.dispatch import Signal
"""
These signals are different from IPN signals in that they are sent the second
the payment is failed or succeeds and come with the `item` object passed to
PayPalPro rather than an IPN object.
### SENDER is the item? is that right???
"""
# Sent when a recurring payments profile is created.
payment_profile_created = Signal()
# Sent when a payment is successfully processed.
payment_was_successful = Signal() #providing_args=["item"])
# Sent when a payment is flagged.
payment_was_flagged = Signal() #providing_args=["item"])
recurring_cancel = Signal()
recurring_suspend = Signal()
recurring_reactivate = Signal()

View file

@ -1,22 +0,0 @@
<html>
<head>
<title></title>
</head>
<body>
<form action="" method="post">
<table>
<tr>
{{ form.as_table }}
<td colspan="2" align="right"><input type="submit" value="confirm"/></td>
</tr>
</table>
</form>
</body>
</html>

View file

@ -1,32 +0,0 @@
<html>
<head>
<title></title>
</head>
<body>
<form action="" method="post">
<table>
<tbody>
{% if errors %}
<tr>
<td colspan="2" align="center">{{ errors }}</td>
</tr>
{% endif %}
<tr>
<td colspan="2" align="center"><a href="?express">Pay by PayPal</a></td>
</tr>
{{ form.as_table }}
<tr>
<td colspan="2" align="right"><input type="submit"/></td>
</tr>
</tbody>
</table>
</form>
</body>
</html>

View file

@ -1,279 +0,0 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from decimal import Decimal
import mock
import warnings
from django.conf import settings
from django.forms import ValidationError
from django.test import TestCase
from django.test.client import RequestFactory
from paypal.pro.fields import CreditCardField
from paypal.pro.helpers import PayPalWPP, PayPalError, VERSION
from paypal.pro.exceptions import PayPalFailure
from paypal.pro.signals import payment_was_successful
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&timestamp=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"]
class CreditCardFieldTest(TestCase):
def test_CreditCardField(self):
field = CreditCardField()
field.clean('4797503429879309')
self.assertEqual(field.card_type, "Visa")
self.assertRaises(ValidationError, CreditCardField().clean, '1234567890123455')
def test_invalidCreditCards(self):
self.assertEqual(CreditCardField().clean('4797-5034-2987-9309'), '4797503429879309')
class PayPalWPPTest(TestCase):
def setUp(self):
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/'
}
# Handle different parameters for Express Checkout
self.ec_item = {
'paymentrequest_0_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 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_with_signal(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.got_signal = False
self.signal_obj = None
def handle_signal(sender, **kwargs):
self.got_signal = True
self.signal_obj = sender
payment_was_successful.connect(handle_signal)
self.assertTrue(self.wpp.doDirectPayment(data))
self.assertTrue(self.got_signal)
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.ec_item)
self.assertEqual(nvp_obj.ack, "Success")
@mock.patch.object(PayPalWPP, '_request', autospec=True)
def test_setExpressCheckout_deprecation(self, mock_request_object):
mock_request_object.return_value = 'ack=Success&token=EC-XXXX&version=%s'
item = self.ec_item.copy()
item.update({'amt': item['paymentrequest_0_amt']})
del item['paymentrequest_0_amt']
with warnings.catch_warnings(record=True) as warning_list:
nvp_obj = self.wpp.setExpressCheckout(item)
# Make sure our warning was given
self.assertTrue(any(warned.category == DeprecationWarning
for warned in warning_list))
# Make sure the method still went through
call_args = mock_request_object.call_args
self.assertIn('PAYMENTREQUEST_0_AMT=%s' % item['amt'],
call_args[0][1])
self.assertEqual(nvp_obj.ack, "Success")
@mock.patch.object(PayPalWPP, '_request', autospec=True)
def test_doExpressCheckoutPayment(self, mock_request_object):
ec_token = 'EC-1234567890'
payerid = 'LXYZABC1234'
item = self.ec_item.copy()
item.update({'token': ec_token, 'payerid': payerid})
mock_request_object.return_value = 'ack=Success&token=%s&version=%spaymentinfo_0_amt=%s' % \
(ec_token, VERSION, self.ec_item['paymentrequest_0_amt'])
wpp = PayPalWPP(REQUEST)
wpp.doExpressCheckoutPayment(item)
call_args = mock_request_object.call_args
self.assertIn('VERSION=%s' % VERSION, call_args[0][1])
self.assertIn('METHOD=DoExpressCheckoutPayment', call_args[0][1])
self.assertIn('TOKEN=%s' % ec_token, call_args[0][1])
self.assertIn('PAYMENTREQUEST_0_AMT=%s' % item['paymentrequest_0_amt'],
call_args[0][1])
self.assertIn('PAYERID=%s' % payerid, call_args[0][1])
@mock.patch.object(PayPalWPP, '_request', autospec=True)
def test_doExpressCheckoutPayment_invalid(self, mock_request_object):
ec_token = 'EC-1234567890'
payerid = 'LXYZABC1234'
item = self.ec_item.copy()
item.update({'token': ec_token, 'payerid': payerid})
mock_request_object.return_value = 'ack=Failure&l_errorcode=42&l_longmessage0=Broken'
wpp = PayPalWPP(REQUEST)
with self.assertRaises(PayPalFailure):
nvp = wpp.doExpressCheckoutPayment(item)
@mock.patch.object(PayPalWPP, '_request', autospec=True)
def test_doExpressCheckoutPayment_deprecation(self, mock_request_object):
mock_request_object.return_value = 'ack=Success&token=EC-XXXX&version=%s'
ec_token = 'EC-1234567890'
payerid = 'LXYZABC1234'
item = self.ec_item.copy()
item.update({'amt': item['paymentrequest_0_amt'],
'token': ec_token,
'payerid': payerid})
del item['paymentrequest_0_amt']
with warnings.catch_warnings(record=True) as warning_list:
nvp_obj = self.wpp.doExpressCheckoutPayment(item)
# Make sure our warning was given
self.assertTrue(any(warned.category == DeprecationWarning
for warned in warning_list))
# Make sure the method still went through
call_args = mock_request_object.call_args
self.assertIn('PAYMENTREQUEST_0_AMT=%s' % item['amt'],
call_args[0][1])
self.assertEqual(nvp_obj.ack, "Success")
@mock.patch.object(PayPalWPP, '_request', autospec=True)
def test_createBillingAgreement(self, mock_request_object):
mock_request_object.return_value = 'ack=Success&billingagreementid=B-XXXXX&version=%s' % VERSION
wpp = PayPalWPP(REQUEST)
nvp = wpp.createBillingAgreement({'token': 'dummy token'})
call_args = mock_request_object.call_args
self.assertIn('VERSION=%s' % VERSION, call_args[0][1])
self.assertIn('METHOD=CreateBillingAgreement', call_args[0][1])
self.assertIn('TOKEN=dummy+token', call_args[0][1])
self.assertEqual(nvp.method, 'CreateBillingAgreement')
self.assertEqual(nvp.ack, 'Success')
mock_request_object.return_value = 'ack=Failure&l_errorcode=42&l_longmessage0=Broken'
with self.assertRaises(PayPalFailure):
nvp = wpp.createBillingAgreement({'token': 'dummy token'})
@mock.patch.object(PayPalWPP, '_request', autospec=True)
def test_doReferenceTransaction_valid(self, mock_request_object):
reference_id = 'B-1234'
amount = Decimal('10.50')
mock_request_object.return_value = 'ack=Success&paymentstatus=Completed&amt=%s&version=%s&billingagreementid=%s' % \
(amount, VERSION, reference_id)
wpp = PayPalWPP(REQUEST)
nvp = wpp.doReferenceTransaction({'referenceid': reference_id,
'amt': amount})
call_args = mock_request_object.call_args
self.assertIn('VERSION=%s' % VERSION, call_args[0][1])
self.assertIn('METHOD=DoReferenceTransaction', call_args[0][1])
self.assertIn('REFERENCEID=%s' % reference_id, call_args[0][1])
self.assertIn('AMT=%s' % amount, call_args[0][1])
self.assertEqual(nvp.method, 'DoReferenceTransaction')
self.assertEqual(nvp.ack, 'Success')
@mock.patch.object(PayPalWPP, '_request', autospec=True)
def test_doReferenceTransaction_invalid(self, mock_request_object):
reference_id = 'B-1234'
amount = Decimal('10.50')
mock_request_object.return_value = 'ack=Failure&l_errorcode=42&l_longmessage0=Broken'
wpp = PayPalWPP(REQUEST)
with self.assertRaises(PayPalFailure):
nvp = wpp.doReferenceTransaction({'referenceid': reference_id,
'amt': amount})
### DoExpressCheckoutPayment
# PayPal Request:
# {'amt': '10.00',
# 'cancelurl': u'http://xxx.xxx.xxx.xxx/deploy/480/upgrade/?upgrade=cname',
# 'custom': u'website_id=480&cname=1',
# 'inv': u'website-480-cname',
# 'method': 'DoExpressCheckoutPayment',
# 'next': u'http://xxx.xxx.xxx.xxx/deploy/480/upgrade/?upgrade=cname',
# 'payerid': u'BN5JZ2V7MLEV4',
# 'paymentaction': 'Sale',
# 'returnurl': u'http://xxx.xxx.xxx.xxx/deploy/480/upgrade/?upgrade=cname',
# 'token': u'EC-6HW17184NE0084127'}
#
# PayPal Response:
# {'ack': 'Success',
# 'amt': '10.00',
# 'build': '848077',
# 'correlationid': '375f4773c3d34',
# 'currencycode': 'USD',
# 'feeamt': '0.59',
# 'ordertime': '2009-03-04T20:56:08Z',
# 'paymentstatus': 'Completed',
# 'paymenttype': 'instant',
# 'pendingreason': 'None',
# 'reasoncode': 'None',
# 'taxamt': '0.00',
# 'timestamp': '2009-03-04T20:56:09Z',
# 'token': 'EC-6HW17184NE0084127',
# 'transactionid': '3TG42202A7335864V',
# 'transactiontype': 'expresscheckout',
# 'version': '54.0'}

View file

@ -1,199 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.conf import settings
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.utils.http import urlencode
from paypal.pro.forms import PaymentForm, ConfirmForm
from paypal.pro.helpers import PayPalWPP
from paypal.pro.exceptions import PayPalFailure
# PayPal Edit IPN URL:
# https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_profile-ipn-notify
EXPRESS_ENDPOINT = "https://www.paypal.com/webscr?cmd=_express-checkout&%s"
SANDBOX_EXPRESS_ENDPOINT = "https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&%s"
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 getattr(settings, 'PAYPAL_TEST', True):
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)
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():
wpp.createRecurringPaymentsProfile(self.item)
else:
wpp.doExpressCheckoutPayment(self.item)
except PayPalFailure:
self.context['errors'] = self.errors['processing']
return self.render_payment_form()
else:
return HttpResponseRedirect(self.success_url)

View file

View file

@ -1,26 +0,0 @@
from django.conf import settings
class PayPalSettingsError(Exception):
"""Raised when settings be bad."""
RECEIVER_EMAIL = settings.PAYPAL_RECEIVER_EMAIL
# API Endpoints.
POSTBACK_ENDPOINT = "https://www.paypal.com/cgi-bin/webscr"
SANDBOX_POSTBACK_ENDPOINT = "https://www.sandbox.paypal.com/cgi-bin/webscr"
# Images
IMAGE = getattr(settings, "PAYPAL_IMAGE", "http://images.paypal.com/images/x-click-but01.gif")
SUBSCRIPTION_IMAGE = getattr(settings, "PAYPAL_SUBSCRIPTION_IMAGE",
"https://www.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif")
DONATION_IMAGE = getattr(settings, "PAYPAL_DONATION_IMAGE", "https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif")
SANDBOX_IMAGE = getattr(settings, "PAYPAL_SANDBOX_IMAGE",
"https://www.sandbox.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif")
SUBSCRIPTION_SANDBOX_IMAGE = getattr(settings, "PAYPAL_SUBSCRIPTION_SANDBOX_IMAGE",
"https://www.sandbox.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif")
DONATION_SANDBOX_IMAGE = getattr(settings, "PAYPAL_DONATION_SANDBOX_IMAGE",
"https://www.sandbox.paypal.com/en_US/i/btn/btn_donateCC_LG.gif")

View file

@ -1,242 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django import forms
from django.utils.safestring import mark_safe
from paypal.standard.widgets import ValueHiddenInput, ReservedValueHiddenInput
from paypal.standard.conf import (POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT,
RECEIVER_EMAIL,
IMAGE, SUBSCRIPTION_IMAGE, DONATION_IMAGE,
SANDBOX_IMAGE, SUBSCRIPTION_SANDBOX_IMAGE, DONATION_SANDBOX_IMAGE)
from django.conf import settings
# 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",)
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'<form action="https://www.paypal.com/cgi-bin/webscr" method="post"> ...'
"""
CMD_CHOICES = (
("_xclick", "Buy now or Donations"),
("_donations", "Donations"),
("_cart", "Shopping cart"),
("_xclick-subscriptions", "Subscribe")
)
SHIPPING_CHOICES = ((1, "No shipping"), (0, "Shipping"))
NO_NOTE_CHOICES = ((1, "No Note"), (0, "Include Note"))
RECURRING_PAYMENT_CHOICES = (
(1, "Subscription Payments Recur"),
(0, "Subscription payments do not recur")
)
REATTEMPT_ON_FAIL_CHOICES = (
(1, "reattempt billing on Failure"),
(0, "Do Not reattempt on failure")
)
BUY = 'buy'
SUBSCRIBE = 'subscribe'
DONATE = 'donate'
# Where the money goes.
business = forms.CharField(widget=ValueHiddenInput(), initial=RECEIVER_EMAIL)
# Item information.
amount = forms.IntegerField(widget=ValueHiddenInput())
item_name = forms.CharField(widget=ValueHiddenInput())
item_number = forms.CharField(widget=ValueHiddenInput())
quantity = forms.CharField(widget=ValueHiddenInput())
# Subscription Related.
a1 = forms.CharField(widget=ValueHiddenInput()) # Trial 1 Price
p1 = forms.CharField(widget=ValueHiddenInput()) # Trial 1 Duration
t1 = forms.CharField(widget=ValueHiddenInput()) # Trial 1 unit of Duration, default to Month
a2 = forms.CharField(widget=ValueHiddenInput()) # Trial 2 Price
p2 = forms.CharField(widget=ValueHiddenInput()) # Trial 2 Duration
t2 = forms.CharField(widget=ValueHiddenInput()) # Trial 2 unit of Duration, default to Month
a3 = forms.CharField(widget=ValueHiddenInput()) # Subscription Price
p3 = forms.CharField(widget=ValueHiddenInput()) # Subscription Duration
t3 = forms.CharField(widget=ValueHiddenInput()) # Subscription unit of Duration, default to Month
src = forms.CharField(widget=ValueHiddenInput()) # Is billing recurring? default to yes
sra = forms.CharField(widget=ValueHiddenInput()) # Reattempt billing on failed cc transaction
no_note = forms.CharField(widget=ValueHiddenInput())
# Can be either 1 or 2. 1 = modify or allow new subscription creation, 2 = modify only
modify = forms.IntegerField(widget=ValueHiddenInput()) # Are we modifying an existing subscription?
# Localization / PayPal Setup
lc = forms.CharField(widget=ValueHiddenInput())
page_style = forms.CharField(widget=ValueHiddenInput())
cbt = forms.CharField(widget=ValueHiddenInput())
# IPN control.
notify_url = forms.CharField(widget=ValueHiddenInput())
cancel_return = forms.CharField(widget=ValueHiddenInput())
return_url = forms.CharField(widget=ReservedValueHiddenInput(attrs={"name": "return"}))
custom = forms.CharField(widget=ValueHiddenInput())
invoice = forms.CharField(widget=ValueHiddenInput())
# Default fields.
cmd = forms.ChoiceField(widget=forms.HiddenInput(), initial=CMD_CHOICES[0][0])
charset = forms.CharField(widget=forms.HiddenInput(), initial="utf-8")
currency_code = forms.CharField(widget=forms.HiddenInput(), initial="USD")
no_shipping = forms.ChoiceField(widget=forms.HiddenInput(), choices=SHIPPING_CHOICES,
initial=SHIPPING_CHOICES[0][0])
def __init__(self, button_type="buy", *args, **kwargs):
super(PayPalPaymentsForm, self).__init__(*args, **kwargs)
self.button_type = button_type
if 'initial' in kwargs:
# Dynamically create, so we can support everything PayPal does.
for k, v in kwargs['initial'].items():
if k not in self.base_fields:
self.fields[k] = forms.CharField(label=k, widget=ValueHiddenInput(), initial=v)
def test_mode(self):
return getattr(settings, 'PAYPAL_TEST', True)
def get_endpoint(self):
"Returns the endpoint url for the form."
if self.test_mode():
return SANDBOX_POSTBACK_ENDPOINT
else:
return POSTBACK_ENDPOINT
def render(self):
return mark_safe(u"""<form action="%s" method="post">
%s
<input type="image" src="%s" border="0" name="submit" alt="Buy it Now" />
</form>""" % (self.get_endpoint(), self.as_p(), self.get_image()))
def sandbox(self):
"Deprecated. Use self.render() instead."
import warnings
warnings.warn("""PaypalPaymentsForm.sandbox() is deprecated.
Use the render() method instead.""", DeprecationWarning)
return self.render()
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,
}[self.test_mode(), self.button_type]
def is_transaction(self):
return not self.is_subscription()
def is_donation(self):
return self.button_type == self.DONATE
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.items():
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"""
<input type="hidden" name="cmd" value="_s-xclick" />
<input type="hidden" name="encrypted" value="%s" />
""" % 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
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)

View file

@ -1,72 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import hashlib
from django.conf import settings
from django.utils.encoding import smart_str
def get_sha1_hexdigest(salt, raw_password):
return hashlib.sha1(smart_str(salt) + smart_str(raw_password)).hexdigest()
def duplicate_txn_id(ipn_obj):
"""
Returns True if a record with this transaction id exists and its
payment_status has not changed.
This function has been completely changed from its previous implementation
where it used to specifically only check for a Pending->Completed
transition.
"""
# get latest similar transaction(s)
similars = ipn_obj._default_manager.filter(txn_id=ipn_obj.txn_id).order_by('-created_at')[:1]
if len(similars) > 0:
# we have a similar transaction, has the payment_status changed?
return similars[0].payment_status == ipn_obj.payment_status
return False
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.
# @@@ 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)
secret = get_sha1_hexdigest(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

View file

@ -1,69 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.contrib import admin
from paypal.standard.ipn.models import PayPalIPN
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_currency", "mc_gross", "mc_fee", "mc_handling", "mc_shipping",
"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)

View file

@ -1,134 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='PayPalIPN',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('business', models.CharField(help_text=b'Email where the money was sent.', 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(max_length=19, verbose_name=b'Parent Transaction ID', 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)),
('txn_id', models.CharField(help_text=b'PayPal transaction ID.', max_length=19, verbose_name=b'Transaction ID', db_index=True, blank=True)),
('txn_type', models.CharField(help_text=b'PayPal transaction type.', max_length=128, verbose_name=b'Transaction Type', 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(help_text=b'ISO 3166', 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=b'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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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=17, 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', null=True, blank=True)),
('subscr_date', models.DateTimeField(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', null=True, blank=True)),
('subscr_effective', models.DateTimeField(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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=b'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)),
('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)),
],
options={
'db_table': 'paypal_ipn',
'verbose_name': 'PayPal IPN',
},
bases=(models.Model,),
),
]

View file

@ -1,17 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from paypal.standard.forms import PayPalStandardBaseForm
from paypal.standard.ipn.models import PayPalIPN
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
exclude = []

View file

@ -1,288 +0,0 @@
# -*- coding: utf-8 -*-
from django.db import models
from south.db import db
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')
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']

View file

@ -1,211 +0,0 @@
# -*- coding: utf-8 -*-
from south.db import db
from south.v2 import SchemaMigration
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'PayPalIPN.txn_id'
db.alter_column('paypal_ipn', 'txn_id', self.gf('django.db.models.fields.CharField')(max_length=19))
# Adding index on 'PayPalIPN', fields ['txn_id']
db.create_index('paypal_ipn', ['txn_id'])
# Changing field 'PayPalIPN.payment_status'
db.alter_column('paypal_ipn', 'payment_status', self.gf('django.db.models.fields.CharField')(max_length=17))
# Changing field 'PayPalIPN.txn_type'
db.alter_column('paypal_ipn', 'txn_type', self.gf('django.db.models.fields.CharField')(max_length=128))
# Changing field 'PayPalIPN.parent_txn_id'
db.alter_column('paypal_ipn', 'parent_txn_id', self.gf('django.db.models.fields.CharField')(max_length=19))
# Changing field 'PayPalIPN.ipaddress'
db.alter_column('paypal_ipn', 'ipaddress', self.gf('django.db.models.fields.IPAddressField')(max_length=15))
def backwards(self, orm):
# Removing index on 'PayPalIPN', fields ['txn_id']
db.delete_index('paypal_ipn', ['txn_id'])
# Changing field 'PayPalIPN.txn_id'
db.alter_column('paypal_ipn', 'txn_id', self.gf('models.CharField')("Transaction ID", max_length=19))
# Changing field 'PayPalIPN.payment_status'
db.alter_column('paypal_ipn', 'payment_status', self.gf('models.CharField')(max_length=9))
# Changing field 'PayPalIPN.txn_type'
db.alter_column('paypal_ipn', 'txn_type', self.gf('models.CharField')("Transaction Type", max_length=128))
# Changing field 'PayPalIPN.parent_txn_id'
db.alter_column('paypal_ipn', 'parent_txn_id',
self.gf('models.CharField')("Parent Transaction ID", max_length=19))
# Changing field 'PayPalIPN.ipaddress'
db.alter_column('paypal_ipn', 'ipaddress', self.gf('models.IPAddressField')())
models = {
'ipn.paypalipn': {
'Meta': {'object_name': 'PayPalIPN', 'db_table': "'paypal_ipn'"},
'address_city': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'address_country': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'address_country_code': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'address_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'address_state': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'address_status': ('django.db.models.fields.CharField', [], {'max_length': '11', 'blank': 'True'}),
'address_street': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'address_zip': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount1': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount2': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount3': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount_per_cycle': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'auction_buyer_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'auction_closing_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'auction_multi_item': (
'django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'auth_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'auth_exp': ('django.db.models.fields.CharField', [], {'max_length': '28', 'blank': 'True'}),
'auth_id': ('django.db.models.fields.CharField', [], {'max_length': '19', 'blank': 'True'}),
'auth_status': ('django.db.models.fields.CharField', [], {'max_length': '9', 'blank': 'True'}),
'business': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'case_creation_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'case_id': ('django.db.models.fields.CharField', [], {'max_length': '14', 'blank': 'True'}),
'case_type': ('django.db.models.fields.CharField', [], {'max_length': '24', 'blank': 'True'}),
'charset': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'contact_phone': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'currency_code': (
'django.db.models.fields.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
'custom': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'exchange_rate': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16',
'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'flag': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'flag_code': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'flag_info': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'for_auction': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'from_view': (
'django.db.models.fields.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
'handling_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_payment_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'invoice': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'ipaddress': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'blank': 'True'}),
'item_name': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'item_number': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'mc_amount1': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_amount2': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_amount3': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_currency': (
'django.db.models.fields.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
'mc_fee': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'mc_gross': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'mc_handling': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_shipping': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'memo': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'next_payment_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'notify_version': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'num_cart_items': (
'django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'option_name1': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'option_name2': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'outstanding_balance': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'parent_txn_id': ('django.db.models.fields.CharField', [], {'max_length': '19', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '24', 'blank': 'True'}),
'payer_business_name': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'payer_email': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'payer_id': ('django.db.models.fields.CharField', [], {'max_length': '13', 'blank': 'True'}),
'payer_status': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
'payment_cycle': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'payment_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'payment_gross': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'payment_status': ('django.db.models.fields.CharField', [], {'max_length': '17', 'blank': 'True'}),
'payment_type': ('django.db.models.fields.CharField', [], {'max_length': '7', 'blank': 'True'}),
'pending_reason': ('django.db.models.fields.CharField', [], {'max_length': '14', 'blank': 'True'}),
'period1': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'period2': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'period3': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'period_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'product_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'product_type': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'profile_status': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'protection_eligibility': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'quantity': ('django.db.models.fields.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}),
'query': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'reason_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
'reattempt': ('django.db.models.fields.CharField', [], {'max_length': '1', 'blank': 'True'}),
'receipt_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'receiver_email': ('django.db.models.fields.EmailField', [], {'max_length': '127', 'blank': 'True'}),
'receiver_id': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'recur_times': (
'django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'recurring': ('django.db.models.fields.CharField', [], {'max_length': '1', 'blank': 'True'}),
'recurring_payment_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'remaining_settle': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'residence_country': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}),
'response': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'retry_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'rp_invoice_id': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'settle_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'settle_currency': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'shipping': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'shipping_method': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'subscr_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'subscr_effective': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'subscr_id': ('django.db.models.fields.CharField', [], {'max_length': '19', 'blank': 'True'}),
'tax': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'test_ipn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'time_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'transaction_entity': ('django.db.models.fields.CharField', [], {'max_length': '7', 'blank': 'True'}),
'transaction_subject': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'txn_id': (
'django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '19', 'blank': 'True'}),
'txn_type': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'verify_sign': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
}
}
complete_apps = ['ipn']

View file

@ -1,63 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from six import b
from six.moves.urllib.request import urlopen
from paypal.standard.models import PayPalStandardBase
from vendor.paypal.standard.ipn.signals import payment_was_flagged, payment_was_refunded, payment_was_reversed, payment_was_successful, recurring_create, recurring_payment, recurring_cancel, recurring_skipped, recurring_failed, subscription_cancel, subscription_signup, subscription_eot, subscription_modify
class PayPalIPN(PayPalStandardBase):
"""Logs PayPal IPN interactions."""
format = u"<IPN: %s %s>"
class Meta:
db_table = "paypal_ipn"
verbose_name = "PayPal IPN"
def _postback(self):
"""Perform PayPal Postback validation."""
return urlopen(self.get_endpoint(), b("cmd=_notify-validate&%s" % self.query)).read()
def _verify_postback(self):
if self.response != "VERIFIED":
self.set_flag("Invalid postback. ({0})".format(self.response))
def send_signals(self):
"""Shout for the world to hear whether a txn was successful."""
if self.flag:
payment_was_flagged.send(sender=self)
# Transaction signals:
if self.is_transaction():
if self.is_refund():
payment_was_refunded.send(sender=self)
elif self.is_reversed():
payment_was_reversed.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)

View file

@ -1,43 +0,0 @@
"""
Note that sometimes you will get duplicate signals emitted, depending on configuration of your systems.
If you do encounter this, you will need to add the "dispatch_uid" to your connect handlers:
http://code.djangoproject.com/wiki/Signals#Helppost_saveseemstobeemittedtwiceforeachsave
"""
from django.dispatch import Signal
# Sent when a payment is successfully processed.
payment_was_successful = Signal()
# Sent when a payment is flagged.
payment_was_flagged = Signal()
# Sent when a payment was refunded by the seller.
payment_was_refunded = Signal()
# Sent when a payment was reversed by the buyer.
payment_was_reversed = Signal()
# Sent when a subscription was cancelled.
subscription_cancel = Signal()
# Sent when a subscription expires.
subscription_eot = Signal()
# Sent when a subscription was modified.
subscription_modify = Signal()
# Sent when a subscription is created.
subscription_signup = Signal()
# recurring_payment_profile_created
recurring_create = Signal()
# recurring_payment
recurring_payment = Signal()
recurring_cancel = Signal()
recurring_skipped = Signal()
recurring_failed = Signal()

View file

@ -1,26 +0,0 @@
<html>
<head>
<title></title>
</head>
<body>
<form action="" method="post">
<table>
{{ form.as_p }}
<tr>
<td colspan="2" align="right">
<input type="submit"/>
</td>
</tr>
</table>
</form>
</body>
</html>

View file

@ -1,44 +0,0 @@
<html>
<head>
<title></title>
<head>
<body>
<form action="http://216.19.180.83:8000/ipn/" method="post">
<input type="text" name="protection_eligibility" value="Ineligible"/>
<input type="text" name="last_name" value="User"/>
<input type="text" name="txn_id" value="51403485VH153354B"/>
<input type="text" name="receiver_email" value="bishan_1233270560_biz@gmail.com"/>
<input type="text" name="payment_status" value="Completed"/>
<input type="text" name="payment_gross" value="10.00"/>
<input type="text" name="tax" value="0.00"/>
<input type="text" name="residence_country" value="US"/>
<input type="text" name="invoice" value="0004"/>
<input type="text" name="payer_status" value="verified"/>
<input type="text" name="txn_type" value="express_checkout"/>
<input type="text" name="handling_amount" value="0.00"/>
<input type="text" name="payment_date" value="23:04:06 Feb 02, 2009 PST"/>
<input type="text" name="first_name" value="Test"/>
<input type="text" name="item_name" value=""/>
<input type="text" name="charset" value="windows-1252"/>
<input type="text" name="custom" value="website_id=13&user_id=21"/>
<input type="text" name="notify_version" value="2.6"/>
<input type="text" name="transaction_subject" value=""/>
<input type="text" name="test_ipn" value="1"/>
<input type="text" name="item_number" value=""/>
<input type="text" name="receiver_id" value="258DLEHY2BDK6"/>
<input type="text" name="payer_id" value="BN5JZ2V7MLEV4"/>
<input type="text" name="verify_sign" value="An5ns1Kso7MWUdW4ErQKJJJ4qi4-AqdZy6dD.sGO3sDhTf1wAbuO2IZ7"/>
<input type="text" name="payment_fee" value="0.59"/>
<input type="text" name="mc_fee" value="0.59"/>
<input type="text" name="mc_currency" value="USD"/>
<input type="text" name="shipping" value="0.00"/>
<input type="text" name="payer_email" value="bishan_1233269544_per@gmail.com"/>
<input type="text" name="payment_type" value="instant"/>
<input type="text" name="mc_gross" value="10.00"/>
<input type="text" name="quantity" value="1"/>
<input type="submit"/>
</form>
</body>
</html>

View file

@ -1,17 +0,0 @@
<html>
<head>
<title></title>
</head>
<body>
{{ form.sandbox }}
</body>
</html>

View file

@ -1,2 +0,0 @@
from .test_ipn import *
from .test_forms import *

View file

@ -1,22 +0,0 @@
from django.test import TestCase
from paypal.standard.forms import PayPalPaymentsForm
class PaymentsFormTest(TestCase):
def test_form_render(self):
f = PayPalPaymentsForm(initial={'business':'me@mybusiness.com',
'amount': '10.50',
'shipping': '2.00',
})
rendered = f.render()
self.assertIn('''action="https://www.sandbox.paypal.com/cgi-bin/webscr"''', rendered)
self.assertIn('''value="me@mybusiness.com"''', rendered)
self.assertIn('''value="2.00"''', rendered)
self.assertIn('''value="10.50"''', rendered)
self.assertIn('''buynowCC''', rendered)
def test_form_endpont(self):
with self.settings(PAYPAL_TEST=False):
f = PayPalPaymentsForm(initial={})
self.assertNotIn('sandbox', f.render())

View file

@ -1,332 +0,0 @@
from django.conf import settings
from django.test import TestCase
from six import b
from six.moves.urllib.parse import urlencode
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, payment_was_refunded, payment_was_reversed,
recurring_skipped, recurring_failed,
recurring_create, recurring_payment, recurring_cancel)
# Parameters are all bytestrings, so we can construct a bytestring
# request the same way that Paypal does.
IPN_POST_PARAMS = {
"protection_eligibility": b("Ineligible"),
"last_name": b("User"),
"txn_id": b("51403485VH153354B"),
"receiver_email": b(settings.PAYPAL_RECEIVER_EMAIL),
"payment_status": b("Completed"),
"payment_gross": b("10.00"),
"tax": b("0.00"),
"residence_country": b("US"),
"invoice": b("0004"),
"payer_status": b("verified"),
"txn_type": b("express_checkout"),
"handling_amount": b("0.00"),
"payment_date": b("23:04:06 Feb 02, 2009 PST"),
"first_name": b("J\xF6rg"),
"item_name": b(""),
"charset": b("windows-1252"),
"custom": b("website_id=13&user_id=21"),
"notify_version": b("2.6"),
"transaction_subject": b(""),
"test_ipn": b("1"),
"item_number": b(""),
"receiver_id": b("258DLEHY2BDK6"),
"payer_id": b("BN5JZ2V7MLEV4"),
"verify_sign": b("An5ns1Kso7MWUdW4ErQKJJJ4qi4-AqdZy6dD.sGO3sDhTf1wAbuO2IZ7"),
"payment_fee": b("0.59"),
"mc_fee": b("0.59"),
"mc_currency": b("USD"),
"shipping": b("0.00"),
"payer_email": b("bishan_1233269544_per@gmail.com"),
"payment_type": b("instant"),
"mc_gross": b("10.00"),
"quantity": b("1"),
}
class IPNTestBase(TestCase):
urls = 'paypal.standard.ipn.tests.test_urls'
def setUp(self):
self.payment_was_successful_receivers = payment_was_successful.receivers
self.payment_was_flagged_receivers = payment_was_flagged.receivers
self.payment_was_refunded_receivers = payment_was_refunded.receivers
self.payment_was_reversed_receivers = payment_was_reversed.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 = []
payment_was_refunded.receivers = []
payment_was_reversed.receivers = []
recurring_skipped.receivers = []
recurring_failed.receivers = []
recurring_create.receivers = []
recurring_payment.receivers = []
recurring_cancel.receivers = []
def tearDown(self):
payment_was_successful.receivers = self.payment_was_successful_receivers
payment_was_flagged.receivers = self.payment_was_flagged_receivers
payment_was_refunded.receivers = self.payment_was_refunded_receivers
payment_was_reversed.receivers = self.payment_was_reversed_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 paypal_post(self, params):
"""
Does an HTTP POST the way that PayPal does, using the params given.
"""
# We build params into a bytestring ourselves, to avoid some encoding
# processing that is done by the test client.
post_data = urlencode(params)
return self.client.post("/ipn/", post_data, content_type='application/x-www-form-urlencoded')
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.paypal_post(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)
return ipn_obj
def assertFlagged(self, updates, flag_info):
params = IPN_POST_PARAMS.copy()
params.update(updates)
response = self.paypal_post(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)
return ipn_obj
class IPNTest(IPNTestBase):
def setUp(self):
# Monkey patch over PayPalIPN to make it get a VERFIED response.
self.old_postback = PayPalIPN._postback
PayPalIPN._postback = lambda self: b("VERIFIED")
def tearDown(self):
PayPalIPN._postback = self.old_postback
def test_correct_ipn(self):
ipn_obj = self.assertGotSignal(payment_was_successful, False)
# Check some encoding issues:
self.assertEqual(ipn_obj.first_name, u"J\u00f6rg")
def test_failed_ipn(self):
PayPalIPN._postback = lambda self: b("INVALID")
self.assertGotSignal(payment_was_flagged, True)
def test_ipn_missing_charset(self):
params = IPN_POST_PARAMS.copy()
del params['charset']
self.assertGotSignal(payment_was_flagged, True, params=params)
def test_refunded_ipn(self):
update = {
"payment_status": "Refunded"
}
params = IPN_POST_PARAMS.copy()
params.update(update)
self.assertGotSignal(payment_was_refunded, False, params)
def test_with_na_date(self):
update = {
"payment_status": "Refunded",
"time_created": "N/A"
}
params = IPN_POST_PARAMS.copy()
params.update(update)
self.assertGotSignal(payment_was_refunded, False, params)
def test_reversed_ipn(self):
update = {
"payment_status": "Reversed"
}
params = IPN_POST_PARAMS.copy()
params.update(update)
self.assertGotSignal(payment_was_reversed, False, params)
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": "Failure"}
flag_info = u"Invalid payment_status. (Failure)"
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.paypal_post(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.paypal_post(IPN_POST_PARAMS)
self.paypal_post(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.paypal_post(params)
self.assertEqual(response.status_code, 200)
ipns = PayPalIPN.objects.all()
self.assertEqual(len(ipns), 1)
self.assertFalse(self.got_signal)
def test_posted_params_attribute(self):
params = {'btn_id1': b('3453595'),
'business': b('email-facilitator@gmail.com'),
'charset': b('windows-1252'),
'custom': b('blahblah'),
"first_name": b("J\xF6rg"),
'ipn_track_id': b('a48170aadb705'),
'item_name1': b('Romanescoins'),
'item_number1': b(''),
'last_name': b('LASTNAME'),
'mc_currency': b('EUR'),
'mc_fee': b('0.35'),
'mc_gross': b('3.00'),
'mc_gross_1': b('3.00'),
'mc_handling': b('0.00'),
'mc_handling1': b('0.00'),
'mc_shipping': b('0.00'),
'mc_shipping1': b('0.00'),
'notify_version': b('3.8'),
'num_cart_items': b('1'),
'payer_email': b('email@gmail.com'),
'payer_id': b('6EQ6SKDFMPU36'),
'payer_status': b('verified'),
'payment_date': b('03:06:57 Jun 27, 2014 PDT'),
'payment_fee': b(''),
'payment_gross': b(''),
'payment_status': b('Completed'),
'payment_type': b('instant'),
'protection_eligibility': b('Ineligible'),
'quantity1': b('3'),
'receiver_email': b('email-facilitator@gmail.com'),
'receiver_id': b('UCWM6R2TARF36'),
'residence_country': b('FR'),
'tax': b('0.00'),
'tax1': b('0.00'),
'test_ipn': b('1'),
'transaction_subject': b('blahblah'),
'txn_id': b('KW31266C37C2593K4'),
'txn_type': b('cart'),
'verify_sign': b('A_SECRET_CODE')}
self.paypal_post(params)
ipn = PayPalIPN.objects.get()
self.assertEqual(ipn.posted_data_dict['quantity1'], '3')
self.assertEqual(ipn.posted_data_dict['first_name'], u"J\u00f6rg")
class IPNPostbackTest(IPNTestBase):
"""
Tests an actual postback to PayPal server.
"""
def test_postback(self):
# Incorrect signature means we will always get failure
self.assertFlagged({}, u'Invalid postback. (INVALID)')

View file

@ -1,5 +0,0 @@
from django.conf.urls import patterns
urlpatterns = patterns('paypal.standard.ipn.views',
(r'^ipn/$', 'ipn'),
)

View file

@ -1,5 +0,0 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('paypal.standard.ipn.views',
url(r'^$', 'ipn', name="paypal-ipn"),
)

View file

@ -1,78 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.http import HttpResponse, QueryDict
from django.views.decorators.http import require_POST
from django.views.decorators.csrf import csrf_exempt
from paypal.standard.ipn.forms import PayPalIPNForm
from paypal.standard.ipn.models import PayPalIPN
@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"
# Also, need to cope with custom encoding, which is stored in the body (!).
# Assuming the tolerant parsing of QueryDict and an ASCII-like encoding,
# such as windows-1252, latin1 or UTF8, the following will work:
encoding = request.REQUEST.get('charset', None)
if encoding is None:
flag = "Invalid form - no charset passed, can't decode"
data = None
else:
try:
data = QueryDict(request.body, encoding=encoding).copy()
except LookupError:
data = None
flag = "Invalid form - invalid charset"
if data is not None:
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 as 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 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()
ipn_obj.send_signals()
return HttpResponse("OKAY")

View file

@ -1,337 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
from django.utils.functional import cached_property
from paypal.standard.helpers import duplicate_txn_id, check_secret
from paypal.standard.conf import RECEIVER_EMAIL, POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT
ST_PP_ACTIVE = 'Active'
ST_PP_CANCELLED = 'Cancelled'
ST_PP_CANCELED_REVERSAL = 'Canceled_Reversal'
ST_PP_CLEARED = 'Cleared'
ST_PP_COMPLETED = 'Completed'
ST_PP_CREATED = 'Created'
ST_PP_DENIED = 'Denied'
ST_PP_EXPIRED = 'Expired'
ST_PP_FAILED = 'Failed'
ST_PP_PAID = 'Paid'
ST_PP_PENDING = 'Pending'
ST_PP_PROCESSED = 'Processed'
ST_PP_REFUNDED = 'Refunded'
ST_PP_REFUSED = 'Refused'
ST_PP_REVERSED = 'Reversed'
ST_PP_REWARDED = 'Rewarded'
ST_PP_UNCLAIMED = 'Unclaimed'
ST_PP_UNCLEARED = 'Uncleared'
ST_PP_VOIDED = 'Voided'
try:
from idmapper.models import SharedMemoryModel as Model
except ImportError:
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_CANCELED_REVERSAL,
ST_PP_CLEARED,
ST_PP_COMPLETED, ST_PP_CREATED, ST_PP_DENIED,
ST_PP_EXPIRED, ST_PP_FAILED, ST_PP_PAID,
ST_PP_PENDING, ST_PP_PROCESSED, ST_PP_REFUNDED,
ST_PP_REFUSED, ST_PP_REVERSED, ST_PP_REWARDED,
ST_PP_UNCLAIMED, ST_PP_UNCLEARED, ST_PP_VOIDED,)
# 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=17, 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)
# 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 Paypal sent to us initially
response = models.TextField(blank=True) # What we got back from our request
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)
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)
@cached_property
def posted_data_dict(self):
"""
All the data that PayPal posted to us, as a correctly parsed dictionary of values.
"""
if not self.query:
return None
from django.http import QueryDict
roughdecode = dict(item.split('=', 1) for item in self.query.split('&'))
encoding = roughdecode.get('charset', None)
if encoding is None:
return None
query = self.query.encode('ascii')
data = QueryDict(query, encoding=encoding)
return data.dict()
def is_transaction(self):
return len(self.txn_id) > 0
def is_refund(self):
return self.payment_status == ST_PP_REFUNDED
def is_reversed(self):
return self.payment_status == ST_PP_REVERSED
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_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().decode('ascii')
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()
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()
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."""
raise NotImplementedError
def initialize(self, request):
"""Store the data we'll need to make the postback from the request object."""
if request.method == 'GET':
# PDT only - this data is currently unused
self.query = request.META.get('QUERY_STRING', '')
elif request.method == 'POST':
# The following works if paypal sends an ASCII bytestring, which it does.
self.query = request.body.decode('ascii')
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

View file

@ -1,121 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.contrib import admin
from paypal.standard.pdt.models import PayPalPDT
# 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":
['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',
],
}),
("Subscriber", {
"description": "The information about the Subscription.",
'classes': ('collapse',),
"fields":
['subscr_id',
'subscr_date',
'subscr_effective',
],
}),
("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',
'flag_code',
'flag_info',
],
}),
)
list_display = ["__unicode__",
"flag",
"invoice",
"custom",
"payment_status",
"created_at",
]
search_fields = ["txn_id",
"recurring_payment_id",
]
admin.site.register(PayPalPDT, PayPalPDTAdmin)

View file

@ -1,9 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from paypal.standard.forms import PayPalStandardBaseForm
from paypal.standard.pdt.models import PayPalPDT
class PayPalPDTForm(PayPalStandardBaseForm):
class Meta:
model = PayPalPDT

View file

@ -1,139 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
]
operations = [
migrations.CreateModel(
name='PayPalPDT',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('business', models.CharField(help_text=b'Email where the money was sent.', 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(max_length=19, verbose_name=b'Parent Transaction ID', 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)),
('txn_id', models.CharField(help_text=b'PayPal transaction ID.', max_length=19, verbose_name=b'Transaction ID', db_index=True, blank=True)),
('txn_type', models.CharField(help_text=b'PayPal transaction type.', max_length=128, verbose_name=b'Transaction Type', 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(help_text=b'ISO 3166', 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=b'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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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=17, 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', null=True, blank=True)),
('subscr_date', models.DateTimeField(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', null=True, blank=True)),
('subscr_effective', models.DateTimeField(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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(help_text=b'HH:MM:SS DD Mmm YY, YYYY PST', 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=b'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)),
('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)),
],
options={
'db_table': 'paypal_pdt',
'verbose_name': 'PayPal PDT',
},
bases=(models.Model,),
),
]

View file

@ -1,95 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.db import models
from django.conf import settings
from django.http import QueryDict
from django.utils.http import urlencode
from six.moves.urllib.request import urlopen
from six.moves.urllib.parse import unquote_plus
from paypal.standard.models import PayPalStandardBase
from paypal.standard.conf import POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT
from paypal.standard.pdt.signals import pdt_successful, pdt_failed
# ### Todo: Move this logic to conf.py:
# if paypal.standard.pdt is in installed apps
# ... then check for this setting in conf.py
class PayPalSettingsError(Exception):
"""Raised when settings are incorrect."""
try:
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.")
class PayPalPDT(PayPalStandardBase):
format = u"<PDT: %s %s>"
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"
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 urlopen(self.get_endpoint(), postback_params).read()
def get_endpoint(self):
if getattr(settings, 'PAYPAL_TEST', True):
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
# TODO: this needs testing and probably fixing under Python 3
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:
pass
qd = QueryDict('', mutable=True)
qd.update(response_dict)
qd.update(dict(ipaddress=self.ipaddress, st=self.st, flag_info=self.flag_info, flag=self.flag,
flag_code=self.flag_code))
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)

View file

@ -1,25 +0,0 @@
"""
Note that sometimes you will get duplicate signals emitted, depending on configuration of your systems.
If you do encounter this, you will need to add the "dispatch_uid" to your connect handlers:
http://code.djangoproject.com/wiki/Signals#Helppost_saveseemstobeemittedtwiceforeachsave
"""
from django.dispatch import Signal
# Sent when a payment is successfully processed.
pdt_successful = Signal()
# Sent when a payment is flagged.
pdt_failed = Signal()
# # Sent when a subscription was cancelled.
# subscription_cancel = Signal()
#
# # Sent when a subscription expires.
# subscription_eot = Signal()
#
# # Sent when a subscription was modified.
# subscription_modify = Signal()
#
# # Sent when a subscription ends.
# subscription_signup = Signal()

View file

@ -1,304 +0,0 @@
# -*- coding: utf-8 -*-
from south.db import db
from django.db import models
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']

View file

@ -1,219 +0,0 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Changing field 'PayPalPDT.txn_id'
db.alter_column('paypal_pdt', 'txn_id', self.gf('django.db.models.fields.CharField')(max_length=19))
# Adding index on 'PayPalPDT', fields ['txn_id']
db.create_index('paypal_pdt', ['txn_id'])
# Changing field 'PayPalPDT.payment_status'
db.alter_column('paypal_pdt', 'payment_status', self.gf('django.db.models.fields.CharField')(max_length=17))
# Changing field 'PayPalPDT.txn_type'
db.alter_column('paypal_pdt', 'txn_type', self.gf('django.db.models.fields.CharField')(max_length=128))
# Changing field 'PayPalPDT.parent_txn_id'
db.alter_column('paypal_pdt', 'parent_txn_id', self.gf('django.db.models.fields.CharField')(max_length=19))
# Changing field 'PayPalPDT.ipaddress'
db.alter_column('paypal_pdt', 'ipaddress', self.gf('django.db.models.fields.IPAddressField')(max_length=15))
def backwards(self, orm):
# Removing index on 'PayPalPDT', fields ['txn_id']
db.delete_index('paypal_pdt', ['txn_id'])
# Changing field 'PayPalPDT.txn_id'
db.alter_column('paypal_pdt', 'txn_id', self.gf('models.CharField')("Transaction ID", max_length=19))
# Changing field 'PayPalPDT.payment_status'
db.alter_column('paypal_pdt', 'payment_status', self.gf('models.CharField')(max_length=9))
# Changing field 'PayPalPDT.txn_type'
db.alter_column('paypal_pdt', 'txn_type', self.gf('models.CharField')("Transaction Type", max_length=128))
# Changing field 'PayPalPDT.parent_txn_id'
db.alter_column('paypal_pdt', 'parent_txn_id',
self.gf('models.CharField')("Parent Transaction ID", max_length=19))
# Changing field 'PayPalPDT.ipaddress'
db.alter_column('paypal_pdt', 'ipaddress', self.gf('models.IPAddressField')())
models = {
'pdt.paypalpdt': {
'Meta': {'object_name': 'PayPalPDT', 'db_table': "'paypal_pdt'"},
'address_city': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'address_country': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'address_country_code': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'address_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'address_state': ('django.db.models.fields.CharField', [], {'max_length': '40', 'blank': 'True'}),
'address_status': ('django.db.models.fields.CharField', [], {'max_length': '11', 'blank': 'True'}),
'address_street': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
'address_zip': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount1': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount2': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount3': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'amount_per_cycle': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'amt': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'auction_buyer_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'auction_closing_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'auction_multi_item': (
'django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'auth_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'auth_exp': ('django.db.models.fields.CharField', [], {'max_length': '28', 'blank': 'True'}),
'auth_id': ('django.db.models.fields.CharField', [], {'max_length': '19', 'blank': 'True'}),
'auth_status': ('django.db.models.fields.CharField', [], {'max_length': '9', 'blank': 'True'}),
'business': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'case_creation_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'case_id': ('django.db.models.fields.CharField', [], {'max_length': '14', 'blank': 'True'}),
'case_type': ('django.db.models.fields.CharField', [], {'max_length': '24', 'blank': 'True'}),
'charset': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'cm': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'contact_phone': ('django.db.models.fields.CharField', [], {'max_length': '20', 'blank': 'True'}),
'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'currency_code': (
'django.db.models.fields.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
'custom': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'exchange_rate': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16',
'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'flag': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'flag_code': ('django.db.models.fields.CharField', [], {'max_length': '16', 'blank': 'True'}),
'flag_info': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'for_auction': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'from_view': (
'django.db.models.fields.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}),
'handling_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'initial_payment_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'invoice': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'ipaddress': ('django.db.models.fields.IPAddressField', [], {'max_length': '15', 'blank': 'True'}),
'item_name': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'item_number': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'mc_amount1': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_amount2': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_amount3': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_currency': (
'django.db.models.fields.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}),
'mc_fee': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'mc_gross': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'mc_handling': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'mc_shipping': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'memo': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'next_payment_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'notify_version': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'num_cart_items': (
'django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'option_name1': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'option_name2': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'outstanding_balance': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'parent_txn_id': ('django.db.models.fields.CharField', [], {'max_length': '19', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '24', 'blank': 'True'}),
'payer_business_name': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'payer_email': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'payer_id': ('django.db.models.fields.CharField', [], {'max_length': '13', 'blank': 'True'}),
'payer_status': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'}),
'payment_cycle': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'payment_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'payment_gross': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'payment_status': ('django.db.models.fields.CharField', [], {'max_length': '17', 'blank': 'True'}),
'payment_type': ('django.db.models.fields.CharField', [], {'max_length': '7', 'blank': 'True'}),
'pending_reason': ('django.db.models.fields.CharField', [], {'max_length': '14', 'blank': 'True'}),
'period1': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'period2': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'period3': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'period_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'product_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'product_type': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'profile_status': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'protection_eligibility': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'quantity': ('django.db.models.fields.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}),
'query': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'reason_code': ('django.db.models.fields.CharField', [], {'max_length': '15', 'blank': 'True'}),
'reattempt': ('django.db.models.fields.CharField', [], {'max_length': '1', 'blank': 'True'}),
'receipt_id': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'receiver_email': ('django.db.models.fields.EmailField', [], {'max_length': '127', 'blank': 'True'}),
'receiver_id': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'recur_times': (
'django.db.models.fields.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}),
'recurring': ('django.db.models.fields.CharField', [], {'max_length': '1', 'blank': 'True'}),
'recurring_payment_id': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'remaining_settle': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'residence_country': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}),
'response': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
'retry_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'rp_invoice_id': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}),
'settle_amount': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2',
'blank': 'True'}),
'settle_currency': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'shipping': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'shipping_method': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'sig': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'st': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
'subscr_date': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'subscr_effective': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'subscr_id': ('django.db.models.fields.CharField', [], {'max_length': '19', 'blank': 'True'}),
'tax': ('django.db.models.fields.DecimalField', [],
{'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}),
'test_ipn': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'time_created': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
'transaction_entity': ('django.db.models.fields.CharField', [], {'max_length': '7', 'blank': 'True'}),
'transaction_subject': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'tx': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
'txn_id': (
'django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '19', 'blank': 'True'}),
'txn_type': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '64', 'blank': 'True'}),
'verify_sign': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'})
}
}
complete_apps = ['pdt']

View file

@ -1,38 +0,0 @@
{% extends "base.html" %}
{% block content %}
{% ifequal pdt_obj.st 'SUCCESS' %}
<h1>Transaction complete</h1>
<p>Thank you for your payment</p>
<p>Please print this page for your records</p>
<div>
<table>
<tr>
<td>Payer:</td>
<td>{{ pdt_obj.first_name }} {{ pdt_obj.last_name }}</td>
</tr>
<tr>
<td>Payer Email:</td>
<td>{{ pdt_obj.payer_email }}</td>
</tr>
<tr>
<td>Amount:</td>
<td>{{ pdt_obj.mc_currency }} {{ pdt_obj.mc_gross }}</td>
</tr>
<tr>
<td>Reference:</td>
<td>{{ pdt_obj.txn_id }}</td>
</tr>
</table>
</div>
{% else %}
<h1>Transaction Failed</h1>
<p>Sorry transaction failed, please try a different form of payment</p>
{% endifequal %}
{% endblock %}

View file

@ -1,35 +0,0 @@
{{st}}
mc_gross={{mc_gross}}
invoice=66
settle_amount=289.83
protection_eligibility=Ineligible
payer_id=8MZ9FQTSAMUPJ
tax=0.00
payment_date=04%3A53%3A52+Apr+12%2C+2009+PDT
payment_status=Completed
charset=windows-1252
first_name=Test
mc_fee=6.88
exchange_rate=1.32876
settle_currency=USD
custom={{custom}}
payer_status=verified
business={{business}}
quantity=1
payer_email=buyer_1239119200_per%40yoursite.com
txn_id={{txn_id}}
payment_type=instant
last_name=User
receiver_email={{business}}
payment_fee=
receiver_id=746LDC2EQAP4W
txn_type=web_accept
item_name=Advertising+Campaign%3A+1+Month+%28225.00%29
mc_currency=EUR
item_number=
residence_country=US
handling_amount=0.00
transaction_subject={{custom}}
payment_gross=
shipping=0.00
-

View file

@ -1 +0,0 @@
from test_pdt import *

View file

@ -1,31 +0,0 @@
{% ifequal pdt_obj.st 'SUCCESS' %}
<h1>Transaction complete</h1>
<p>Thank you for your payment</p>
<p>Please print this page for your records</p>
<div>
<table>
<tr>
<td>Payer:</td>
<td>{{ pdt_obj.first_name }} {{ pdt_obj.last_name }}</td>
</tr>
<tr>
<td>Payer Email:</td>
<td>{{ pdt_obj.payer_email }}</td>
</tr>
<tr>
<td>Amount:</td>
<td>{{ pdt_obj.mc_currency }} {{ pdt_obj.mc_gross }}</td>
</tr>
<tr>
<td>Reference:</td>
<td>{{ pdt_obj.txn_id }}</td>
</tr>
</table>
</div>
{% else %}
<h1>Transaction Failed</h1>
<p>Sorry transaction failed, please try a different form of payment</p>
{% endifequal %}

View file

@ -1,120 +0,0 @@
"""
run this with ./manage.py test website
see http://www.djangoproject.com/documentation/testing/ for details
"""
import os
from django.conf import settings
from django.shortcuts import render_to_response
from django.test import TestCase
from paypal.standard.pdt.models import PayPalPDT
from paypal.standard.pdt.signals import pdt_successful, pdt_failed
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
class PDTTest(TestCase):
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 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_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'])

View file

@ -1,5 +0,0 @@
from django.conf.urls import patterns
urlpatterns = patterns('paypal.standard.pdt.views',
(r'^pdt/$', 'pdt'),
)

View file

@ -1,5 +0,0 @@
from django.conf.urls import patterns, url
urlpatterns = patterns('paypal.standard.pdt.views',
url(r'^$', 'pdt', name="paypal-pdt"),
)

View file

@ -1,66 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.template import RequestContext
from django.shortcuts import render_to_response
from django.views.decorators.http import require_GET
from paypal.standard.pdt.models import PayPalPDT
from paypal.standard.pdt.forms import PayPalPDTForm
@require_GET
def pdt(request, item_check_callable=None, template="pdt/pdt.html", context=None):
"""Standard implementation of a view that processes PDT and then renders a template
For more advanced uses, create your own view and call process_pdt.
"""
pdt_obj, failed = process_pdt(request, item_check_callable)
context = context or {}
context.update({"failed": failed, "pdt_obj": pdt_obj})
return render_to_response(template, context, RequestContext(request))
def process_pdt(request, item_check_callable=None):
"""
Payment data transfer implementation: http://tinyurl.com/c9jjmw
This function returns a tuple of pdt_obj and failed
pdt_obj is an object of type PayPalPDT
failed is a flag that indeicates whether the transaction was processed successfully
"""
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 as 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
return (pdt_obj, failed)

View file

@ -1,38 +0,0 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django import forms
try:
from django.forms.utils import flatatt # Django 1.7 and later
except ImportError:
from django.forms.util import flatatt # earlier
from django.utils.safestring import mark_safe
from django.utils.encoding import force_text
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)
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_text(value)
return mark_safe(u'<input%s />' % flatatt(final_attrs))