Merge branch 'tastypie2' of github.com:Gluejar/regluit into tastypie2
commit
2423051df6
|
@ -0,0 +1,131 @@
|
||||||
|
# encoding: 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):
|
||||||
|
|
||||||
|
# Adding model 'UserProfile'
|
||||||
|
db.create_table('core_userprofile', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], unique=True)),
|
||||||
|
('tagline', self.gf('django.db.models.fields.CharField')(max_length=140, blank=True)),
|
||||||
|
))
|
||||||
|
db.send_create_signal('core', ['UserProfile'])
|
||||||
|
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
|
||||||
|
# Deleting model 'UserProfile'
|
||||||
|
db.delete_table('core_userprofile')
|
||||||
|
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'auth.group': {
|
||||||
|
'Meta': {'object_name': 'Group'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
|
||||||
|
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'auth.permission': {
|
||||||
|
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
|
||||||
|
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
|
||||||
|
},
|
||||||
|
'auth.user': {
|
||||||
|
'Meta': {'object_name': 'User'},
|
||||||
|
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
|
||||||
|
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
|
||||||
|
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
|
||||||
|
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
|
||||||
|
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
|
||||||
|
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
|
||||||
|
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
|
||||||
|
},
|
||||||
|
'contenttypes.contenttype': {
|
||||||
|
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
|
||||||
|
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
|
||||||
|
},
|
||||||
|
'core.author': {
|
||||||
|
'Meta': {'object_name': 'Author'},
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
|
||||||
|
'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
|
||||||
|
'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'authors'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
|
||||||
|
},
|
||||||
|
'core.campaign': {
|
||||||
|
'Meta': {'object_name': 'Campaign'},
|
||||||
|
'amazon_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'deadline': ('django.db.models.fields.DateTimeField', [], {}),
|
||||||
|
'description': ('django.db.models.fields.CharField', [], {'max_length': '10000'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
|
||||||
|
'paypal_receiver': ('django.db.models.fields.CharField', [], {'max_length': '100', 'null': 'True'}),
|
||||||
|
'target': ('django.db.models.fields.FloatField', [], {}),
|
||||||
|
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'campaigns'", 'to': "orm['core.Work']"})
|
||||||
|
},
|
||||||
|
'core.edition': {
|
||||||
|
'Meta': {'object_name': 'Edition'},
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'description': ('django.db.models.fields.TextField', [], {'default': "''", 'null': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'isbn_10': ('django.db.models.fields.CharField', [], {'max_length': '10', 'null': 'True'}),
|
||||||
|
'isbn_13': ('django.db.models.fields.CharField', [], {'max_length': '13', 'null': 'True'}),
|
||||||
|
'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
|
||||||
|
'publication_date': ('django.db.models.fields.CharField', [], {'max_length': '50'}),
|
||||||
|
'publisher': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'}),
|
||||||
|
'work': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'editions'", 'null': 'True', 'to': "orm['core.Work']"})
|
||||||
|
},
|
||||||
|
'core.editioncover': {
|
||||||
|
'Meta': {'object_name': 'EditionCover'},
|
||||||
|
'edition': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'covers'", 'to': "orm['core.Edition']"}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'openlibrary_id': ('django.db.models.fields.IntegerField', [], {})
|
||||||
|
},
|
||||||
|
'core.subject': {
|
||||||
|
'Meta': {'object_name': 'Subject'},
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'name': ('django.db.models.fields.CharField', [], {'max_length': '500'}),
|
||||||
|
'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'subjects'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
|
||||||
|
},
|
||||||
|
'core.userprofile': {
|
||||||
|
'Meta': {'object_name': 'UserProfile'},
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'tagline': ('django.db.models.fields.CharField', [], {'max_length': '140', 'blank': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'unique': 'True'})
|
||||||
|
},
|
||||||
|
'core.wishlist': {
|
||||||
|
'Meta': {'object_name': 'Wishlist'},
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'wishlist'", 'unique': 'True', 'to': "orm['auth.User']"}),
|
||||||
|
'works': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'wishlists'", 'symmetrical': 'False', 'to': "orm['core.Work']"})
|
||||||
|
},
|
||||||
|
'core.work': {
|
||||||
|
'Meta': {'object_name': 'Work'},
|
||||||
|
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'openlibrary_id': ('django.db.models.fields.CharField', [], {'max_length': '50', 'null': 'True'}),
|
||||||
|
'title': ('django.db.models.fields.CharField', [], {'max_length': '1000'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['core']
|
|
@ -85,5 +85,8 @@ class Wishlist(models.Model):
|
||||||
user = models.OneToOneField(User, related_name='wishlist')
|
user = models.OneToOneField(User, related_name='wishlist')
|
||||||
works = models.ManyToManyField('Work', related_name='wishlists')
|
works = models.ManyToManyField('Work', related_name='wishlists')
|
||||||
|
|
||||||
|
class UserProfile(models.Model):
|
||||||
|
user = models.ForeignKey(User, unique=True)
|
||||||
|
tagline = models.CharField(max_length=140, blank=True)
|
||||||
|
|
||||||
from regluit.core import signals
|
from regluit.core import signals
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
from django import forms
|
||||||
|
from django.db import models
|
||||||
|
#from django.forms import Form, ModelForm, Textarea, CharField, ValidationError, RegexField
|
||||||
|
from regluit.core.models import UserProfile
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
class ProfileForm(forms.ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = UserProfile
|
||||||
|
exclude = 'user'
|
||||||
|
widgets = {
|
||||||
|
'tagline': forms.Textarea(attrs={'cols': 70, 'rows': 2}),
|
||||||
|
}
|
||||||
|
|
||||||
|
class UserData(forms.Form):
|
||||||
|
username = forms.RegexField(
|
||||||
|
label=_("New Username"),
|
||||||
|
max_length=30,
|
||||||
|
regex=r'^[\w.@+-]+$',
|
||||||
|
help_text = _("30 characters or less."),
|
||||||
|
error_messages = {
|
||||||
|
'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
# oldusername = forms.CharField(max_length=30)
|
||||||
|
|
||||||
|
|
||||||
|
def clean_username(self):
|
||||||
|
username = self.data["username"]
|
||||||
|
oldusername = self.data["oldusername"]
|
||||||
|
if username != oldusername:
|
||||||
|
try:
|
||||||
|
User.objects.get(username=username)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
return username
|
||||||
|
raise forms.ValidationError(_("Another user with that username already exists."))
|
||||||
|
raise forms.ValidationError(_("Your username is already "+oldusername))
|
|
@ -1,6 +1,9 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
{# raw url references raise test errors in tests for django registration; this is a workaround #}
|
{# raw url references raise test errors in tests for django registration; this is a workaround #}
|
||||||
{% url privacy as privacyurl %}
|
{% url privacy as privacyurl %}
|
||||||
|
{% url regluit.frontend.views.edit_user as editurl %}
|
||||||
|
{% url rightsholders as rhtoolsurl %}
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>unglue.it {% block title %}{% endblock %}</title>
|
<title>unglue.it {% block title %}{% endblock %}</title>
|
||||||
|
@ -45,9 +48,13 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="footer">
|
<div id="footer">
|
||||||
<ul class="menu">
|
<p>
|
||||||
<li><a href="{{privacyurl}}"><span>Privacy</span></a></li>
|
<a href="{{privacyurl}}"><span>Privacy</span></a>
|
||||||
</ul>
|
<a href="{{rhtools}}"><span>Rightsholder tools</span></a>
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<a href="{{editurl}}"><span>Settings</span></a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Create Profile{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="registration">
|
||||||
|
<h1>Create a new profile for {{ user }} </h1>
|
||||||
|
|
||||||
|
<form method="POST" action="">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form }}
|
||||||
|
<input type="submit" name="submit" value="Save" id="submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Edit Profile{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="registration">
|
||||||
|
<h1>Edit profile for {{ user }} </h1>
|
||||||
|
|
||||||
|
<form method="POST" action="">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<input type="submit" name="submit" value="Update" id="submit">
|
||||||
|
</form>
|
||||||
|
{{ debug }}
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Edit Profile{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="registration">
|
||||||
|
<h1>Profile for {{ user }} </h1>
|
||||||
|
|
||||||
|
<p><b>TagLine:</b> {{ profile.tagline }}</p>
|
||||||
|
<p><a href="/profiles/edit/">Edit Again</a></p>
|
||||||
|
<p><a href="/supporter/{{user|urlencode}}/">{{user}}'s Unglue.it Page</a></p>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
|
@ -0,0 +1,9 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Profile List{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="registration">
|
||||||
|
Sorry, you can't list the profiles on this site.
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{% extends "registration/registration_base.html" %}
|
||||||
|
{% block title %}Change User Data{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<div id="registration">
|
||||||
|
<h1>Changing your Username.</h1>
|
||||||
|
|
||||||
|
<p> If you change your Username, the web address for your profile page will change as well.</p>
|
||||||
|
|
||||||
|
<p> <b>Your current Username:</b> {{ user.username }}</p>
|
||||||
|
<form method="POST" action="">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<input type="submit" name="submit" value="Change" id="submit">
|
||||||
|
</form>
|
||||||
|
<p><a href="/profiles/edit/">Edit Your Profile</a></p>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>unglue.it tools for rightsholders</h1>
|
||||||
|
|
||||||
|
<h2>Rightsholder social media tools</h2>
|
||||||
|
|
||||||
|
Coming soon.
|
||||||
|
|
||||||
|
<h2>Rewards</h2>
|
||||||
|
|
||||||
|
Campaigns have rewards as a way to thank supporters. unglue.it includes a standard set of rewards in all campaigns. You are encouraged to add additional sweeteners to motivate people to donate.
|
||||||
|
|
||||||
|
Here are the standard rewards:
|
||||||
|
<ul>
|
||||||
|
<li><em>Any level</em> — The unglued ebook delivered to your inbox</li>
|
||||||
|
<li><em>$25</em> — Your name under "supporters" in the acknowledgements section</li>
|
||||||
|
<li><em>$50</em> — Your name & link of your choice under "benefactors"</li>
|
||||||
|
<li><em>$100</em> — Your name, link of your choice, & a brief message (140 characters max) under "bibliophiles"</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
|
@ -9,5 +9,7 @@ urlpatterns = patterns(
|
||||||
url(r"^search/$", "search", name="search"),
|
url(r"^search/$", "search", name="search"),
|
||||||
url(r"^privacy/$", TemplateView.as_view(template_name="privacy.html"),
|
url(r"^privacy/$", TemplateView.as_view(template_name="privacy.html"),
|
||||||
name="privacy"),
|
name="privacy"),
|
||||||
|
url(r"^rightsholders/$", TemplateView.as_view(template_name="rhtools.html"),
|
||||||
|
name="rightsholders"),
|
||||||
url(r"^wishlist/$", "wishlist", name="wishlist"),
|
url(r"^wishlist/$", "wishlist", name="wishlist"),
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from django.template import RequestContext
|
from django.template import RequestContext
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
# from django.contrib.auth.forms import UserChangeForm
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
|
@ -10,6 +11,8 @@ from django.shortcuts import render, render_to_response, get_object_or_404
|
||||||
from regluit.core import models, bookloader
|
from regluit.core import models, bookloader
|
||||||
from regluit.core.search import gluejar_search
|
from regluit.core.search import gluejar_search
|
||||||
|
|
||||||
|
from regluit.frontend.forms import UserData
|
||||||
|
|
||||||
def home(request):
|
def home(request):
|
||||||
if request.user.is_authenticated():
|
if request.user.is_authenticated():
|
||||||
return HttpResponseRedirect(reverse('supporter',
|
return HttpResponseRedirect(reverse('supporter',
|
||||||
|
@ -25,6 +28,24 @@ def supporter(request, supporter_username):
|
||||||
}
|
}
|
||||||
return render(request, 'supporter.html', context)
|
return render(request, 'supporter.html', context)
|
||||||
|
|
||||||
|
|
||||||
|
def edit_user(request):
|
||||||
|
form=UserData()
|
||||||
|
if not request.user.is_authenticated():
|
||||||
|
return HttpResponseRedirect(reverse('auth_login'))
|
||||||
|
oldusername=request.user.username
|
||||||
|
if request.method == 'POST':
|
||||||
|
# surely there's a better way to add data to the POST data?
|
||||||
|
postcopy=request.POST.copy()
|
||||||
|
postcopy['oldusername']=oldusername
|
||||||
|
form = UserData(postcopy)
|
||||||
|
if form.is_valid(): # All validation rules pass, go and change the username
|
||||||
|
request.user.username=form.cleaned_data['username']
|
||||||
|
request.user.save()
|
||||||
|
return HttpResponseRedirect(reverse('home')) # Redirect after POST
|
||||||
|
return render(request,'registration/user_change_form.html', {'form': form},)
|
||||||
|
|
||||||
|
|
||||||
def search(request):
|
def search(request):
|
||||||
q = request.GET.get('q', None)
|
q = request.GET.get('q', None)
|
||||||
results = gluejar_search(q)
|
results = gluejar_search(q)
|
||||||
|
|
|
@ -2,7 +2,7 @@ from regluit.core.models import Campaign, Wishlist
|
||||||
from regluit.payment.models import Transaction, Receiver
|
from regluit.payment.models import Transaction, Receiver
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from regluit.payment.parameters import *
|
from regluit.payment.parameters import *
|
||||||
from regluit.payment.paypal import Pay, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, Preapproval
|
from regluit.payment.paypal import Pay, IPN, IPN_TYPE_PAYMENT, IPN_TYPE_PREAPPROVAL, IPN_TYPE_ADJUSTMENT, Preapproval, IPN_PAY_STATUS_COMPLETED, CancelPreapproval, IPN_SENDER_STATUS_COMPLETED
|
||||||
import uuid
|
import uuid
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
@ -27,39 +27,120 @@ class PaymentManager( object ):
|
||||||
|
|
||||||
|
|
||||||
if ipn.transaction_type == IPN_TYPE_PAYMENT:
|
if ipn.transaction_type == IPN_TYPE_PAYMENT:
|
||||||
|
# payment IPN
|
||||||
|
|
||||||
if ipn.preapproval_key:
|
key = ipn.key()
|
||||||
key = ipn.preapproval_key
|
|
||||||
else:
|
|
||||||
key = ipn.key
|
|
||||||
|
|
||||||
t = Transaction.objects.get(reference=key)
|
t = Transaction.objects.get(reference=key)
|
||||||
|
|
||||||
|
# The status is always one of the IPN_PAY_STATUS codes defined in paypal.py
|
||||||
t.status = ipn.status
|
t.status = ipn.status
|
||||||
|
|
||||||
|
|
||||||
for item in ipn.transactions:
|
for item in ipn.transactions:
|
||||||
|
|
||||||
|
try:
|
||||||
r = Receiver.objects.get(transaction=t, email=item['receiver'])
|
r = Receiver.objects.get(transaction=t, email=item['receiver'])
|
||||||
|
print item
|
||||||
|
# one of the IPN_SENDER_STATUS codes defined in paypal.py
|
||||||
r.status = item['status_for_sender_txn']
|
r.status = item['status_for_sender_txn']
|
||||||
|
r.txn_id = item['id_for_sender_txn']
|
||||||
r.save()
|
r.save()
|
||||||
|
except:
|
||||||
|
# Log an excecption if we have a receiver that is not found
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
t.save()
|
t.save()
|
||||||
|
|
||||||
|
elif ipn.transaction_type == IPN_TYPE_ADJUSTMENT:
|
||||||
|
# a chargeback, reversal or refund for an existng payment
|
||||||
|
|
||||||
|
key = ipn.key()
|
||||||
|
t = Transaction.objects.get(reference=key)
|
||||||
|
|
||||||
|
# The status is always one of the IPN_PAY_STATUS codes defined in paypal.py
|
||||||
|
t.status = ipn.status
|
||||||
|
|
||||||
|
# Reason code indicates more details of the adjustment type
|
||||||
|
t.reason = ipn.reason_code
|
||||||
|
|
||||||
|
|
||||||
elif ipn.transaction_type == IPN_TYPE_PREAPPROVAL:
|
elif ipn.transaction_type == IPN_TYPE_PREAPPROVAL:
|
||||||
|
|
||||||
t = Transaction.objects.get(reference=ipn.preapproval_key)
|
|
||||||
|
key = ipn.key()
|
||||||
|
t = Transaction.objects.get(reference=key)
|
||||||
|
|
||||||
|
# The status is always one of the IPN_PREAPPROVAL_STATUS codes defined in paypal.py
|
||||||
t.status = ipn.status
|
t.status = ipn.status
|
||||||
t.save()
|
t.save()
|
||||||
|
print "IPN: Preapproval transaction: " + str(t.id) + " Status: " + ipn.status
|
||||||
|
|
||||||
else:
|
else:
|
||||||
print "IPN: Unknown Transaction Type: " + ipn.transaction_type
|
print "IPN: Unknown Transaction Type: " + ipn.transaction_type
|
||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
print "ERROR: INVALID IPN"
|
||||||
print ipn.error
|
print ipn.error
|
||||||
|
|
||||||
except:
|
except:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
'''
|
||||||
|
Generic query handler for returning summary and transaction info, see query_user, query_list and query_campaign
|
||||||
|
'''
|
||||||
|
def run_query(self, transaction_list, summary, pledged, authorized ):
|
||||||
|
|
||||||
|
if pledged:
|
||||||
|
pledged_list = transaction_list.filter(type=PAYMENT_TYPE_INSTANT,
|
||||||
|
status="COMPLETED")
|
||||||
|
else:
|
||||||
|
pledged_list = []
|
||||||
|
|
||||||
|
if authorized:
|
||||||
|
authorized_list = Transaction.objects.filter(type=PAYMENT_TYPE_AUTHORIZATION,
|
||||||
|
status="ACTIVE")
|
||||||
|
else:
|
||||||
|
authorized_list = []
|
||||||
|
|
||||||
|
if summary:
|
||||||
|
pledged_amount = 0.0
|
||||||
|
authorized_amount = 0.0
|
||||||
|
|
||||||
|
for t in pledged_list:
|
||||||
|
for r in t.receiver_set.all():
|
||||||
|
if r.status == IPN_SENDER_STATUS_COMPLETED:
|
||||||
|
# individual senders may not have been paid due to errors, and disputes/chargebacks only appear here
|
||||||
|
pledged_amount += r.amount
|
||||||
|
|
||||||
|
for t in authorized_list:
|
||||||
|
authorized_amount += t.amount
|
||||||
|
|
||||||
|
amount = pledged_amount + authorized_amount
|
||||||
|
return amount
|
||||||
|
|
||||||
|
else:
|
||||||
|
return pledged_list | authorized_list
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
query_user
|
||||||
|
|
||||||
|
Returns either an amount or list of transactions for a user
|
||||||
|
|
||||||
|
summary: if true, return a float of the total, if false, return a list of transactions
|
||||||
|
pledged: include amounts pledged
|
||||||
|
authorized: include amounts pre-authorized
|
||||||
|
|
||||||
|
return value: either a float summary or a list of transactions
|
||||||
|
|
||||||
|
'''
|
||||||
|
def query_user(self, user, summary=False, pledged=True, authorized=True):
|
||||||
|
|
||||||
|
transactions = Transaction.objects.filter(user=user)
|
||||||
|
return self.run_query(transactions, summary, pledged, authorized)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
query_campaign
|
query_campaign
|
||||||
|
|
||||||
|
@ -74,35 +155,25 @@ class PaymentManager( object ):
|
||||||
'''
|
'''
|
||||||
def query_campaign(self, campaign, summary=False, pledged=True, authorized=True):
|
def query_campaign(self, campaign, summary=False, pledged=True, authorized=True):
|
||||||
|
|
||||||
if pledged:
|
transactions = Transaction.objects.filter(campaign=campaign)
|
||||||
pledged_list = Transaction.objects.filter(campaign=campaign,
|
return self.run_query(transactions, summary, pledged, authorized)
|
||||||
type=PAYMENT_TYPE_INSTANT,
|
|
||||||
status="COMPLETED")
|
|
||||||
else:
|
|
||||||
pledged_list = []
|
|
||||||
|
|
||||||
if authorized:
|
'''
|
||||||
authorized_list = Transaction.objects.filter(campaign=campaign,
|
query_list
|
||||||
type=PAYMENT_TYPE_AUTHORIZATION,
|
|
||||||
status="ACTIVE")
|
|
||||||
else:
|
|
||||||
authorized_list = []
|
|
||||||
|
|
||||||
if summary:
|
Returns either an amount or list of transactions for a list
|
||||||
pledged_amount = 0.0
|
|
||||||
authorized_amount = 0.0
|
|
||||||
|
|
||||||
for t in pledged_list:
|
summary: if true, return a float of the total, if false, return a list of transactions
|
||||||
pledged_amount += t.amount
|
pledged: include amounts pledged
|
||||||
|
authorized: include amounts pre-authorized
|
||||||
|
|
||||||
for t in authorized_list:
|
return value: either a float summary or a list of transactions
|
||||||
authorized_amount += t.amount
|
|
||||||
|
|
||||||
amount = pledged_amount + authorized_amount
|
'''
|
||||||
return amount
|
def query_campaign(self, list, summary=False, pledged=True, authorized=True):
|
||||||
|
|
||||||
else:
|
transactions = Transaction.objects.filter(list=list)
|
||||||
return pledged_list | authorized_list
|
return self.run_query(transactions, summary, pledged, authorized)
|
||||||
|
|
||||||
'''
|
'''
|
||||||
execute_campaign
|
execute_campaign
|
||||||
|
@ -114,12 +185,14 @@ class PaymentManager( object ):
|
||||||
'''
|
'''
|
||||||
def execute_campaign(self, campaign):
|
def execute_campaign(self, campaign):
|
||||||
|
|
||||||
|
# only allow active transactions to go through again, if there is an error, intervention is needed
|
||||||
transactions = Transaction.objects.filter(campaign=campaign, status="ACTIVE")
|
transactions = Transaction.objects.filter(campaign=campaign, status="ACTIVE")
|
||||||
|
|
||||||
for t in transactions:
|
for t in transactions:
|
||||||
|
|
||||||
receiver_list = [{'email':'jakace_1309677337_biz@gmail.com', 'amount':t.amount * 0.80},
|
# BUGBUG: Fill this in with the correct info from the campaign object
|
||||||
{'email':'boogus@gmail.com', 'amount':t.amount * 0.20}]
|
receiver_list = [{'email':'jakace_1309677337_biz@gmail.com', 'amount':t.amount},
|
||||||
|
{'email':'seller_1317463643_biz@gmail.com', 'amount':t.amount * 0.20}]
|
||||||
|
|
||||||
self.execute_transaction(t, receiver_list)
|
self.execute_transaction(t, receiver_list)
|
||||||
|
|
||||||
|
@ -144,13 +217,17 @@ class PaymentManager( object ):
|
||||||
'''
|
'''
|
||||||
def execute_transaction(self, transaction, receiver_list):
|
def execute_transaction(self, transaction, receiver_list):
|
||||||
|
|
||||||
for r in receiver_list:
|
if len(transaction.receiver_set.all()) > 0:
|
||||||
receiver = Receiver.objects.create(email=r['email'], amount=r['amount'], currency=transaction.currency, status="ACTIVE", transaction=transaction)
|
# we are re-submitting a transaction, wipe the old receiver list
|
||||||
|
transaction.receiver_set.all().delete()
|
||||||
|
|
||||||
p = Pay(transaction, receiver_list)
|
transaction.create_receivers(receiver_list)
|
||||||
transaction.status = p.status()
|
|
||||||
|
|
||||||
if p.status() == 'COMPLETED':
|
p = Pay(transaction)
|
||||||
|
|
||||||
|
# We will update our transaction status when we receive the IPN
|
||||||
|
|
||||||
|
if p.status() == IPN_PAY_STATUS_COMPLETED:
|
||||||
print "Execute Success"
|
print "Execute Success"
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -159,6 +236,27 @@ class PaymentManager( object ):
|
||||||
print "Execute Error: " + p.error()
|
print "Execute Error: " + p.error()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
'''
|
||||||
|
cancel
|
||||||
|
|
||||||
|
cancels a pre-approved transaction
|
||||||
|
|
||||||
|
return value: True if successful, false otherwise
|
||||||
|
'''
|
||||||
|
def cancel(self, transaction):
|
||||||
|
|
||||||
|
p = CancelPreapproval(transaction)
|
||||||
|
|
||||||
|
if p.success():
|
||||||
|
print "Cancel Transaction " + str(transaction.id) + " Completed"
|
||||||
|
return True
|
||||||
|
|
||||||
|
else:
|
||||||
|
print "Cancel Transaction " + str(transaction.id) + " Failed with error: " + p.error()
|
||||||
|
transaction.error = p.error()
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
authorize
|
authorize
|
||||||
|
|
||||||
|
@ -191,14 +289,12 @@ class PaymentManager( object ):
|
||||||
p = Preapproval(t, amount)
|
p = Preapproval(t, amount)
|
||||||
|
|
||||||
if p.status() == 'Success':
|
if p.status() == 'Success':
|
||||||
t.status = 'CREATED'
|
|
||||||
t.reference = p.paykey()
|
t.reference = p.paykey()
|
||||||
t.save()
|
t.save()
|
||||||
print "Authorize Success: " + p.next_url()
|
print "Authorize Success: " + p.next_url()
|
||||||
return t, p.next_url()
|
return t, p.next_url()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
t.status = 'ERROR'
|
|
||||||
t.error = p.error()
|
t.error = p.error()
|
||||||
t.save()
|
t.save()
|
||||||
print "Authorize Error: " + p.error()
|
print "Authorize Error: " + p.error()
|
||||||
|
@ -230,8 +326,9 @@ class PaymentManager( object ):
|
||||||
def pledge(self, currency, target, receiver_list, campaign=None, list=None, user=None):
|
def pledge(self, currency, target, receiver_list, campaign=None, list=None, user=None):
|
||||||
|
|
||||||
amount = 0.0
|
amount = 0.0
|
||||||
for r in receiver_list:
|
|
||||||
amount += r['amount']
|
# for chained payments, first amount is the total amount
|
||||||
|
amount = receiver_list[0]['amount']
|
||||||
|
|
||||||
t = Transaction.objects.create(amount=amount,
|
t = Transaction.objects.create(amount=amount,
|
||||||
type=PAYMENT_TYPE_INSTANT,
|
type=PAYMENT_TYPE_INSTANT,
|
||||||
|
@ -244,11 +341,9 @@ class PaymentManager( object ):
|
||||||
user=user
|
user=user
|
||||||
)
|
)
|
||||||
|
|
||||||
for r in receiver_list:
|
t.create_receivers(receiver_list)
|
||||||
receiver = Receiver.objects.create(email=r['email'], amount=r['amount'], currency=currency, status="None", transaction=t)
|
|
||||||
|
|
||||||
p = Pay(t, receiver_list)
|
p = Pay(t)
|
||||||
t.status = p.status()
|
|
||||||
|
|
||||||
if p.status() == 'CREATED':
|
if p.status() == 'CREATED':
|
||||||
t.reference = p.paykey()
|
t.reference = p.paykey()
|
||||||
|
@ -259,7 +354,7 @@ class PaymentManager( object ):
|
||||||
else:
|
else:
|
||||||
t.error = p.error()
|
t.error = p.error()
|
||||||
t.save()
|
t.save()
|
||||||
print "Pledge Status: " + p.status() + "Error: " + p.error()
|
print "Pledge Error: " + p.error()
|
||||||
return t, None
|
return t, None
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,12 @@ class Transaction(models.Model):
|
||||||
reference = models.CharField(max_length=128, null=True)
|
reference = models.CharField(max_length=128, null=True)
|
||||||
receipt = models.CharField(max_length=256, null=True)
|
receipt = models.CharField(max_length=256, null=True)
|
||||||
error = models.CharField(max_length=256, null=True)
|
error = models.CharField(max_length=256, null=True)
|
||||||
|
reason = models.CharField(max_length=64, null=True)
|
||||||
date_created = models.DateTimeField(auto_now_add=True)
|
date_created = models.DateTimeField(auto_now_add=True)
|
||||||
date_modified = models.DateTimeField(auto_now=True)
|
date_modified = models.DateTimeField(auto_now=True)
|
||||||
date_payment = models.DateTimeField(null=True)
|
date_payment = models.DateTimeField(null=True)
|
||||||
date_authorized = models.DateTimeField(null=True)
|
date_authorized = models.DateTimeField(null=True)
|
||||||
|
date_expired = models.DateTimeField(null=True)
|
||||||
user = models.ForeignKey(User, null=True)
|
user = models.ForeignKey(User, null=True)
|
||||||
campaign = models.ForeignKey(Campaign, null=True)
|
campaign = models.ForeignKey(Campaign, null=True)
|
||||||
list = models.ForeignKey(Wishlist, null=True)
|
list = models.ForeignKey(Wishlist, null=True)
|
||||||
|
@ -25,12 +27,23 @@ class Transaction(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u"-- Transaction:\n \tstatus: %s\n \t amount: %s\n \treference: %s\n \terror: %s\n" % (self.status, str(self.amount), self.reference, self.error)
|
return u"-- Transaction:\n \tstatus: %s\n \t amount: %s\n \treference: %s\n \terror: %s\n" % (self.status, str(self.amount), self.reference, self.error)
|
||||||
|
|
||||||
|
def create_receivers(self, receiver_list):
|
||||||
|
|
||||||
|
primary = True
|
||||||
|
for r in receiver_list:
|
||||||
|
receiver = Receiver.objects.create(email=r['email'], amount=r['amount'], currency=self.currency, status="None", primary=primary, transaction=self)
|
||||||
|
primary = False
|
||||||
|
|
||||||
|
|
||||||
class Receiver(models.Model):
|
class Receiver(models.Model):
|
||||||
|
|
||||||
email = models.CharField(max_length=64)
|
email = models.CharField(max_length=64)
|
||||||
amount = models.FloatField()
|
amount = models.FloatField()
|
||||||
currency = models.CharField(max_length=10)
|
currency = models.CharField(max_length=10)
|
||||||
status = models.CharField(max_length=64)
|
status = models.CharField(max_length=64)
|
||||||
|
reason = models.CharField(max_length=64)
|
||||||
|
primary = models.BooleanField()
|
||||||
|
txn_id = models.CharField(max_length=64)
|
||||||
transaction = models.ForeignKey(Transaction)
|
transaction = models.ForeignKey(Transaction)
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@ TARGET_TYPE_NONE = 0
|
||||||
TARGET_TYPE_CAMPAIGN = 1
|
TARGET_TYPE_CAMPAIGN = 1
|
||||||
TARGET_TYPE_LIST = 2
|
TARGET_TYPE_LIST = 2
|
||||||
|
|
||||||
|
|
||||||
PAYPAL_USERNAME = 'jakace_1309677337_biz_api1.gmail.com'
|
PAYPAL_USERNAME = 'jakace_1309677337_biz_api1.gmail.com'
|
||||||
PAYPAL_PASSWORD = '1309677386'
|
PAYPAL_PASSWORD = '1309677386'
|
||||||
PAYPAL_SIGNATURE = 'A543DNCPfye3PpgUquUAuyfN2wNQAt.h8FJqHIro2U3-Z886XQvIdWSy'
|
PAYPAL_SIGNATURE = 'A543DNCPfye3PpgUquUAuyfN2wNQAt.h8FJqHIro2U3-Z886XQvIdWSy'
|
||||||
|
@ -22,3 +21,8 @@ CANCEL_URL = 'paymentcancel'
|
||||||
|
|
||||||
PREAPPROVAL_PERIOD = 365 # days to ask for in a preapproval
|
PREAPPROVAL_PERIOD = 365 # days to ask for in a preapproval
|
||||||
PAYPAL_COMMISSION = 0.10
|
PAYPAL_COMMISSION = 0.10
|
||||||
|
|
||||||
|
try:
|
||||||
|
from local_parameters import *
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
|
@ -30,14 +30,28 @@ IPN_TYPE_PAYMENT = 'Adaptive Payment PAY'
|
||||||
IPN_TYPE_ADJUSTMENT = 'Adjustment'
|
IPN_TYPE_ADJUSTMENT = 'Adjustment'
|
||||||
IPN_TYPE_PREAPPROVAL = 'Adaptive Payment PREAPPROVAL'
|
IPN_TYPE_PREAPPROVAL = 'Adaptive Payment PREAPPROVAL'
|
||||||
|
|
||||||
#status constants
|
#pay API status constants
|
||||||
IPN_STATUS_CREATED = 'CREATED'
|
IPN_PAY_STATUS_NONE = 'NONE'
|
||||||
IPN_STATUS_COMPLETED = 'COMPLETED'
|
IPN_PAY_STATUS_CREATED = 'CREATED'
|
||||||
IPN_STATUS_INCOMPLETE = 'INCOMPLETE'
|
IPN_PAY_STATUS_COMPLETED = 'COMPLETED'
|
||||||
IPN_STATUS_ERROR = 'ERROR'
|
IPN_PAY_STATUS_INCOMPLETE = 'INCOMPLETE'
|
||||||
IPN_STATUS_REVERSALERROR = 'REVERSALERROR'
|
IPN_PAY_STATUS_ERROR = 'ERROR'
|
||||||
IPN_STATUS_PROCESSING = 'PROCESSING'
|
IPN_PAY_STATUS_REVERSALERROR = 'REVERSALERROR'
|
||||||
IPN_STATUS_PENDING = 'PENDING'
|
IPN_PAY_STATUS_PROCESSING = 'PROCESSING'
|
||||||
|
IPN_PAY_STATUS_PENDING = 'PENDING'
|
||||||
|
IPN_PAY_STATUS_ACTIVE = "ACTIVE"
|
||||||
|
IPN_PAY_STATUS_CANCELED = "CANCELED"
|
||||||
|
|
||||||
|
|
||||||
|
IPN_SENDER_STATUS_COMPLETED = 'COMPLETED'
|
||||||
|
IPN_SENDER_STATUS_PENDING = 'PENDING'
|
||||||
|
IPN_SENDER_STATUS_CREATED = 'CREATED'
|
||||||
|
IPN_SENDER_STATUS_PARTIALLY_REFUNDED = 'PARTIALLY_REFUNDED'
|
||||||
|
IPN_SENDER_STATUS_DENIED = 'DENIED'
|
||||||
|
IPN_SENDER_STATUS_PROCESSING = 'PROCESSING'
|
||||||
|
IPN_SENDER_STATUS_REVERSED = 'REVERSED'
|
||||||
|
IPN_SENDER_STATUS_REFUNDED = 'REFUNDED'
|
||||||
|
IPN_SENDER_STATUS_FAILED = 'FAILED'
|
||||||
|
|
||||||
# action_type constants
|
# action_type constants
|
||||||
IPN_ACTION_TYPE_PAY = 'PAY'
|
IPN_ACTION_TYPE_PAY = 'PAY'
|
||||||
|
@ -48,11 +62,13 @@ IPN_TXN_STATUS_COMPLETED = 'Completed'
|
||||||
IPN_TXN_STATUS_PENDING = 'Pending'
|
IPN_TXN_STATUS_PENDING = 'Pending'
|
||||||
IPN_TXN_STATUS_REFUNDED = 'Refunded'
|
IPN_TXN_STATUS_REFUNDED = 'Refunded'
|
||||||
|
|
||||||
IPN_REASON_CODE_CHARGEBACK = 'Chargeback'
|
# addaptive payment adjusted IPN reason codes
|
||||||
IPN_REASON_CODE_SETTLEMENT = 'Settlement'
|
IPN_REASON_CODE_CHARGEBACK_SETTLEMENT = 'Chargeback Settlement'
|
||||||
IPN_REASON_CODE_ADMIN_REVERSAL = 'Admin reversal'
|
IPN_REASON_CODE_ADMIN_REVERSAL = 'Admin reversal'
|
||||||
IPN_REASON_CODE_REFUND = 'Refund'
|
IPN_REASON_CODE_REFUND = 'Refund'
|
||||||
|
|
||||||
|
class PaypalError(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
class url_request( object ):
|
class url_request( object ):
|
||||||
|
|
||||||
|
@ -72,7 +88,7 @@ class url_request( object ):
|
||||||
|
|
||||||
|
|
||||||
class Pay( object ):
|
class Pay( object ):
|
||||||
def __init__( self, transaction, receiver_list):
|
def __init__( self, transaction):
|
||||||
|
|
||||||
headers = {
|
headers = {
|
||||||
'X-PAYPAL-SECURITY-USERID':PAYPAL_USERNAME,
|
'X-PAYPAL-SECURITY-USERID':PAYPAL_USERNAME,
|
||||||
|
@ -88,6 +104,25 @@ class Pay( object ):
|
||||||
print "Return URL: " + return_url
|
print "Return URL: " + return_url
|
||||||
print "Cancel URL: " + cancel_url
|
print "Cancel URL: " + cancel_url
|
||||||
|
|
||||||
|
receiver_list = []
|
||||||
|
receivers = transaction.receiver_set.all()
|
||||||
|
|
||||||
|
if len(receivers) == 0:
|
||||||
|
raise Exception
|
||||||
|
|
||||||
|
for r in receivers:
|
||||||
|
if len(receivers) > 1:
|
||||||
|
if r.primary:
|
||||||
|
primary_string = 'true'
|
||||||
|
else:
|
||||||
|
primary_string = 'false'
|
||||||
|
|
||||||
|
receiver_list.append({'email':r.email,'amount':str(r.amount), 'primary':primary_string})
|
||||||
|
else:
|
||||||
|
receiver_list.append({'email':r.email,'amount':str(r.amount)})
|
||||||
|
|
||||||
|
print receiver_list
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'actionType': 'PAY',
|
'actionType': 'PAY',
|
||||||
'receiverList': { 'receiver': receiver_list },
|
'receiverList': { 'receiver': receiver_list },
|
||||||
|
@ -120,7 +155,7 @@ class Pay( object ):
|
||||||
print error
|
print error
|
||||||
return error[0]['message']
|
return error[0]['message']
|
||||||
else:
|
else:
|
||||||
return None
|
return 'Paypal PAY: Unknown Error'
|
||||||
|
|
||||||
def amount( self ):
|
def amount( self ):
|
||||||
return decimal.Decimal(self.results[ 'payment_gross' ])
|
return decimal.Decimal(self.results[ 'payment_gross' ])
|
||||||
|
@ -132,6 +167,51 @@ class Pay( object ):
|
||||||
return '%s?cmd=_ap-payment&paykey=%s' % ( PAYPAL_PAYMENT_HOST, self.response['payKey'] )
|
return '%s?cmd=_ap-payment&paykey=%s' % ( PAYPAL_PAYMENT_HOST, self.response['payKey'] )
|
||||||
|
|
||||||
|
|
||||||
|
class CancelPreapproval(object):
|
||||||
|
|
||||||
|
def __init__(self, transaction):
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'X-PAYPAL-SECURITY-USERID':PAYPAL_USERNAME,
|
||||||
|
'X-PAYPAL-SECURITY-PASSWORD':PAYPAL_PASSWORD,
|
||||||
|
'X-PAYPAL-SECURITY-SIGNATURE':PAYPAL_SIGNATURE,
|
||||||
|
'X-PAYPAL-APPLICATION-ID':PAYPAL_APPID,
|
||||||
|
'X-PAYPAL-REQUEST-DATA-FORMAT':'JSON',
|
||||||
|
'X-PAYPAL-RESPONSE-DATA-FORMAT':'JSON',
|
||||||
|
}
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'preapprovalKey':transaction.reference,
|
||||||
|
'requestEnvelope': { 'errorLanguage': 'en_US' }
|
||||||
|
}
|
||||||
|
|
||||||
|
self.raw_request = json.dumps(data)
|
||||||
|
self.raw_response = url_request(PAYPAL_ENDPOINT, "/AdaptivePayments/CancelPreapproval", data=self.raw_request, headers=headers ).content()
|
||||||
|
print "paypal CANCEL PREAPPROBAL response was: %s" % self.raw_response
|
||||||
|
self.response = json.loads( self.raw_response )
|
||||||
|
print self.response
|
||||||
|
|
||||||
|
def success(self):
|
||||||
|
if self.status() == 'Success' or self.status() == "SuccessWithWarning":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def error(self):
|
||||||
|
if self.response.has_key('error'):
|
||||||
|
error = self.response['error']
|
||||||
|
print error
|
||||||
|
return error[0]['message']
|
||||||
|
else:
|
||||||
|
return 'Paypal Preapproval Cancel: Unknown Error'
|
||||||
|
|
||||||
|
def status(self):
|
||||||
|
if self.response.has_key( 'responseEnvelope' ) and self.response['responseEnvelope'].has_key( 'ack' ):
|
||||||
|
return self.response['responseEnvelope']['ack']
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Preapproval( object ):
|
class Preapproval( object ):
|
||||||
def __init__( self, transaction, amount ):
|
def __init__( self, transaction, amount ):
|
||||||
|
|
||||||
|
@ -147,14 +227,19 @@ class Preapproval( object ):
|
||||||
return_url = BASE_URL + COMPLETE_URL
|
return_url = BASE_URL + COMPLETE_URL
|
||||||
cancel_url = BASE_URL + CANCEL_URL
|
cancel_url = BASE_URL + CANCEL_URL
|
||||||
|
|
||||||
|
# set the expiration date for the preapproval
|
||||||
now = datetime.datetime.utcnow()
|
now = datetime.datetime.utcnow()
|
||||||
expiry = now + datetime.timedelta( days=PREAPPROVAL_PERIOD )
|
expiry = now + datetime.timedelta( days=PREAPPROVAL_PERIOD )
|
||||||
|
transaction.date_authorized = now
|
||||||
|
transaction.date_expired = expiry
|
||||||
|
transaction.save()
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'endingDate': expiry.isoformat(),
|
'endingDate': expiry.isoformat(),
|
||||||
'startingDate': now.isoformat(),
|
'startingDate': now.isoformat(),
|
||||||
'maxTotalAmountOfAllPayments': '%.2f' % transaction.amount,
|
'maxTotalAmountOfAllPayments': '%.2f' % transaction.amount,
|
||||||
|
'maxNumberOfPayments':1,
|
||||||
|
'maxAmountPerPayment': '%.2f' % transaction.amount,
|
||||||
'currencyCode': transaction.currency,
|
'currencyCode': transaction.currency,
|
||||||
'returnUrl': return_url,
|
'returnUrl': return_url,
|
||||||
'cancelUrl': cancel_url,
|
'cancelUrl': cancel_url,
|
||||||
|
@ -183,7 +268,7 @@ class Preapproval( object ):
|
||||||
print error
|
print error
|
||||||
return error[0]['message']
|
return error[0]['message']
|
||||||
else:
|
else:
|
||||||
return None
|
return 'Paypal Preapproval: Unknown Error'
|
||||||
|
|
||||||
def status( self ):
|
def status( self ):
|
||||||
if self.response.has_key( 'responseEnvelope' ) and self.response['responseEnvelope'].has_key( 'ack' ):
|
if self.response.has_key( 'responseEnvelope' ) and self.response['responseEnvelope'].has_key( 'ack' ):
|
||||||
|
@ -217,18 +302,14 @@ class IPN( object ):
|
||||||
self.error = 'PayPal response was "%s"' % raw_response
|
self.error = 'PayPal response was "%s"' % raw_response
|
||||||
return
|
return
|
||||||
|
|
||||||
# check payment status
|
|
||||||
if request.POST['status'] != 'COMPLETED' and request.POST['status'] != 'ACTIVE':
|
|
||||||
self.error = 'PayPal status was "%s"' % request.POST['status']
|
|
||||||
return
|
|
||||||
|
|
||||||
# Process the details
|
# Process the details
|
||||||
self.status = request.POST.get('status', None)
|
self.status = request.POST.get('status', None)
|
||||||
self.sender_email = request.POST.get('sender_email', None)
|
self.sender_email = request.POST.get('sender_email', None)
|
||||||
self.action_type = request.POST.get('action_type', None)
|
self.action_type = request.POST.get('action_type', None)
|
||||||
self.key = request.POST.get('pay_key', None)
|
self.pay_key = request.POST.get('pay_key', None)
|
||||||
self.preapproval_key = request.POST.get('preapproval_key', None)
|
self.preapproval_key = request.POST.get('preapproval_key', None)
|
||||||
self.transaction_type = request.POST.get('transaction_type', None)
|
self.transaction_type = request.POST.get('transaction_type', None)
|
||||||
|
self.reason_code = request.POST.get('reason_code', None)
|
||||||
|
|
||||||
self.process_transactions(request)
|
self.process_transactions(request)
|
||||||
|
|
||||||
|
@ -236,9 +317,21 @@ class IPN( object ):
|
||||||
self.error = "Error: ServerError"
|
self.error = "Error: ServerError"
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
def key(self):
|
||||||
|
# We only keep one reference, either a prapproval key, or a pay key, for the transaction. This avoids the
|
||||||
|
# race condition that may result if the IPN for an executed pre-approval(with both a pay key and preapproval key) is received
|
||||||
|
# before we have time to store the pay key
|
||||||
|
if self.preapproval_key:
|
||||||
|
return self.preapproval_key
|
||||||
|
elif self.pay_key:
|
||||||
|
return self.pay_key
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def success( self ):
|
def success( self ):
|
||||||
return self.error == None
|
return self.error == None
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def slicedict(cls, d, s):
|
def slicedict(cls, d, s):
|
||||||
return dict((str(k.replace(s, '', 1)), v) for k,v in d.iteritems() if k.startswith(s))
|
return dict((str(k.replace(s, '', 1)), v) for k,v in d.iteritems() if k.startswith(s))
|
||||||
|
|
|
@ -5,6 +5,7 @@ urlpatterns = patterns(
|
||||||
url(r"^testpledge", "testPledge"),
|
url(r"^testpledge", "testPledge"),
|
||||||
url(r"^testauthorize", "testAuthorize"),
|
url(r"^testauthorize", "testAuthorize"),
|
||||||
url(r"^testexecute", "testExecute"),
|
url(r"^testexecute", "testExecute"),
|
||||||
|
url(r"^testcancel", "testCancel"),
|
||||||
url(r"^querycampaign", "queryCampaign"),
|
url(r"^querycampaign", "queryCampaign"),
|
||||||
url(r"^paypalipn", "paypalIPN")
|
url(r"^paypalipn", "paypalIPN")
|
||||||
)
|
)
|
||||||
|
|
|
@ -57,7 +57,7 @@ def testExecute(request):
|
||||||
|
|
||||||
# Note, set this to 1-5 different receivers with absolute amounts for each
|
# Note, set this to 1-5 different receivers with absolute amounts for each
|
||||||
receiver_list = [{'email':'jakace_1309677337_biz@gmail.com', 'amount':t.amount * 0.80},
|
receiver_list = [{'email':'jakace_1309677337_biz@gmail.com', 'amount':t.amount * 0.80},
|
||||||
{'email':'boogus@gmail.com', 'amount':t.amount * 0.20}]
|
{'email':'seller_1317463643_biz@gmail.com', 'amount':t.amount * 0.20}]
|
||||||
|
|
||||||
p.execute_transaction(t, receiver_list)
|
p.execute_transaction(t, receiver_list)
|
||||||
output += str(t)
|
output += str(t)
|
||||||
|
@ -88,7 +88,7 @@ def testAuthorize(request):
|
||||||
|
|
||||||
# Note, set this to 1-5 different receivers with absolute amounts for each
|
# Note, set this to 1-5 different receivers with absolute amounts for each
|
||||||
receiver_list = [{'email':'jakace_1309677337_biz@gmail.com', 'amount':20.00},
|
receiver_list = [{'email':'jakace_1309677337_biz@gmail.com', 'amount':20.00},
|
||||||
{'email':'boogus@gmail.com', 'amount':10.00}]
|
{'email':'seller_1317463643_biz@gmail.com', 'amount':10.00}]
|
||||||
|
|
||||||
if campaign_id:
|
if campaign_id:
|
||||||
campaign = Campaign.objects.get(id=int(campaign_id))
|
campaign = Campaign.objects.get(id=int(campaign_id))
|
||||||
|
@ -106,6 +106,25 @@ def testAuthorize(request):
|
||||||
print "testAuthorize: Error " + str(t.reference)
|
print "testAuthorize: Error " + str(t.reference)
|
||||||
return HttpResponse(response)
|
return HttpResponse(response)
|
||||||
|
|
||||||
|
'''
|
||||||
|
http://BASE/testcancel?transaction=2
|
||||||
|
|
||||||
|
Example that cancels a preapproved transaction
|
||||||
|
'''
|
||||||
|
def testCancel(request):
|
||||||
|
|
||||||
|
if "transaction" not in request.GET.keys():
|
||||||
|
return HttpResponse("No Transaction in Request")
|
||||||
|
|
||||||
|
t = Transaction.objects.get(id=int(request.GET['transaction']))
|
||||||
|
p = PaymentManager()
|
||||||
|
if p.cancel(t):
|
||||||
|
return HttpResponse("Success")
|
||||||
|
else:
|
||||||
|
message = "Error: " + t.error
|
||||||
|
return HttpResponse(message)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
http://BASE/testpledge?campaign=2
|
http://BASE/testpledge?campaign=2
|
||||||
|
|
||||||
|
@ -122,8 +141,7 @@ def testPledge(request):
|
||||||
|
|
||||||
|
|
||||||
# Note, set this to 1-5 different receivers with absolute amounts for each
|
# Note, set this to 1-5 different receivers with absolute amounts for each
|
||||||
receiver_list = [{'email':'jakace_1309677337_biz@gmail.com', 'amount':20.00},
|
receiver_list = [{'email':'rh1_1317336251_biz@gluejar.com', 'amount':20.00},]
|
||||||
{'email':'boogus@gmail.com', 'amount':10.00}]
|
|
||||||
|
|
||||||
if campaign_id:
|
if campaign_id:
|
||||||
campaign = Campaign.objects.get(id=int(campaign_id))
|
campaign = Campaign.objects.get(id=int(campaign_id))
|
||||||
|
|
|
@ -5,3 +5,4 @@ https://github.com/toastdriven/django-tastypie/tarball/master
|
||||||
requests
|
requests
|
||||||
https://bitbucket.org/ubernostrum/django-registration/get/tip.tar.gz
|
https://bitbucket.org/ubernostrum/django-registration/get/tip.tar.gz
|
||||||
django-social-auth
|
django-social-auth
|
||||||
|
django-profiles
|
||||||
|
|
|
@ -107,6 +107,7 @@ INSTALLED_APPS = (
|
||||||
'registration',
|
'registration',
|
||||||
'social_auth',
|
'social_auth',
|
||||||
'tastypie',
|
'tastypie',
|
||||||
|
'profiles',
|
||||||
)
|
)
|
||||||
|
|
||||||
# A sample logging configuration. The only tangible logging
|
# A sample logging configuration. The only tangible logging
|
||||||
|
@ -169,6 +170,8 @@ AUTHENTICATION_BACKENDS = (
|
||||||
|
|
||||||
SOCIAL_AUTH_ENABLED_BACKENDS = ['google', 'facebook', 'twitter']
|
SOCIAL_AUTH_ENABLED_BACKENDS = ['google', 'facebook', 'twitter']
|
||||||
SOCIAL_AUTH_ASSOCIATE_BY_MAIL = True
|
SOCIAL_AUTH_ASSOCIATE_BY_MAIL = True
|
||||||
|
SOCIAL_AUTH_NEW_USER_REDIRECT_URL = '/accounts/edit/'
|
||||||
|
|
||||||
FACEBOOK_EXTENDED_PERMISSIONS = ['email']
|
FACEBOOK_EXTENDED_PERMISSIONS = ['email']
|
||||||
|
|
||||||
LOGIN_URL = "/accounts/login/"
|
LOGIN_URL = "/accounts/login/"
|
||||||
|
@ -178,3 +181,5 @@ LOGOUT_URL = "/accounts/logout/"
|
||||||
USER_AGENT = "unglue.it.bot v0.0.1 <http://unglue.it>"
|
USER_AGENT = "unglue.it.bot v0.0.1 <http://unglue.it>"
|
||||||
|
|
||||||
SOUTH_TESTS_MIGRATE = False
|
SOUTH_TESTS_MIGRATE = False
|
||||||
|
|
||||||
|
AUTH_PROFILE_MODULE = "core.userprofile"
|
4
urls.py
4
urls.py
|
@ -1,11 +1,15 @@
|
||||||
from django.conf.urls.defaults import *
|
from django.conf.urls.defaults import *
|
||||||
|
from frontend.forms import ProfileForm
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
url(r'^accounts/activate/complete/$','django.contrib.auth.views.login',
|
url(r'^accounts/activate/complete/$','django.contrib.auth.views.login',
|
||||||
{'template_name': 'registration/activation_complete.html'}),
|
{'template_name': 'registration/activation_complete.html'}),
|
||||||
|
(r'^accounts/edit/$', 'regluit.frontend.views.edit_user'),
|
||||||
(r'^accounts/', include('registration.backends.default.urls')),
|
(r'^accounts/', include('registration.backends.default.urls')),
|
||||||
(r'^socialauth/', include('social_auth.urls')),
|
(r'^socialauth/', include('social_auth.urls')),
|
||||||
(r'^api/', include('regluit.api.urls')),
|
(r'^api/', include('regluit.api.urls')),
|
||||||
|
('^profiles/edit/$', 'profiles.views.edit_profile', {'form_class': ProfileForm,}),
|
||||||
|
(r'^profiles/', include('profiles.urls')),
|
||||||
(r'', include('regluit.frontend.urls')),
|
(r'', include('regluit.frontend.urls')),
|
||||||
(r'', include('regluit.payment.urls'))
|
(r'', include('regluit.payment.urls'))
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue