Reputation: 1016
I have an online store where users can pay each other to buy things, I have been testing it with sandbox accounts but I don't think it's working. I really can't get where the issue is
Here is my views.py:
def payment_process(request, trade_id):
trade = get_object_or_404(Trade, id=trade_id)
host = request.get_host()
paypal_dict = {
'business': trade.seller.email,
'amount': Decimal(trade.price),
'item_name': trade.filename,
'invoice': str(trade.id),
'currency_code': 'USD',
'notify_url': 'https://{}{}'.format(host,
reverse('paypal-ipn')),
'return_url': 'https://{}{}/{}'.format(host,
*reverse('payment_done', kwargs={'trade_id': trade.id})),
'cancel_return': 'https://{}{}'.format(host,
reverse('home')),
}
form = PayPalPaymentsForm(initial=paypal_dict)
return render(request, 'payment/payment_process.html', {'trade': trade, 'form': form})
@csrf_exempt
def payment_done(request, trade_id):
# Do some very important stuff after paying ...
# It would be really nice if someone can help me with a checker
messages.success(request, 'Your product is in your inbox now')
return redirect('trade:inbox')
My urls.py:
urlpatterns = [
path('admin/', admin.site.urls),
...
# Prodbox Payment
path('payment/process/<int:trade_id>/', payment_views.payment_process, name="payment_process"),
path('payment/done/<int:trade_id>/', payment_views.payment_done, name="payment_done"),
# Prodbox packages
path('paypal/', include('paypal.standard.ipn.urls')),
]
The template which handles paying:
{% extends 'users/base.html' %}
{% block title %}Payment Process | Prodbox {% endblock title %}
{% block content %}
<div class="container row justify-content-center">
<div class="shadow-lg p-3 mb-5 col-md-8 bg-white rounded m-4 p-4">
<section>
<p>Seller: {{ trade.seller.email }}</p>
<p>Product: {{ trade.thing }}</p>
<p style="color: #2ecc71;">Price: ${{ trade.price }}</p>
</section>
<section>
<h4>Pay with PayPal</h4>
{{ form.render }}
</section>
</div>
</div>
{% endblock content %}
It's very very important to redirect users to payment_done view after finish paying, (it would be nice if I had a checker to check if the payment is completed before running done function)
Also, note that I'm emphasizing on users to use their PayPal email account
So why it's not working?!
User model:
from django.db import models
from django.contrib.auth.models import AbstractUser, BaseUserManager
class CustomUserManager(BaseUserManager):
"""
Custom user model manager where email is the unique identifiers
for authentication instead of usernames.
"""
def create_user(self, email, password, **extra_fields):
"""
Create and save a User with the given email and password.
"""
if not email:
raise ValueError(_('The Email must be set'))
email = self.normalize_email(email)
user = self.model(email=email, **extra_fields)
user.set_password(password)
user.save()
return user
def create_superuser(self, email, password, **extra_fields):
"""
Create and save a SuperUser with the given email and password.
"""
extra_fields.setdefault('is_staff', True)
extra_fields.setdefault('is_superuser', True)
extra_fields.setdefault('is_active', True)
if extra_fields.get('is_staff') is not True:
raise ValueError(_('Superuser must have is_staff=True.'))
if extra_fields.get('is_superuser') is not True:
raise ValueError(_('Superuser must have is_superuser=True.'))
return self.create_user(email, password, **extra_fields)
class User(AbstractUser):
username = None
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField(('email address'), unique=True)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
objects = CustomUserManager()
def username(self):
return f'{self.first_name} {self.last_name}'
def __str__(self):
return self.email
settings.py:
AUTH_USER_MODEL = 'users.User'
PAYPAL_RECEIVER_EMAIL = '[email protected]'
PAYPAL_TEST = False
local_settings.py:
DEBUG = True
ALLOWED_HOSTS = []
PAYPAL_RECEIVER_EMAIL = '[email protected]'
PAYPAL_TEST = True
Upvotes: 0
Views: 499
Reputation: 30377
You say it's not working yet provide no information about the problem behavior and why it's not working.
But I suppose that doesn't matter too much, since you're using a bad integration (django-paypal, based on payments standard) for the desired behavior you want of it being "very very important" that the payer return.
The integration you should switch to is to integrate v2/checkout/orders, with or without the Checkout-Python-SDK. You will need two routes on your server, one for 'Set Up Transaction' and one for 'Capture Transaction', documented here: https://developer.paypal.com/docs/checkout/reference/server-integration/
The best front-end UI to use for approval is here: https://developer.paypal.com/demo/checkout/#/pattern/server . Get this working well in a standalone HTML file that calls your 2 django backend routes (via fetch), before you then integrate it as a front-end into your django templates and checkout flow.
For the feature of a user paying another user, use the payee
object, documented here: https://developer.paypal.com/docs/checkout/integration-features/pay-another-account/
Upvotes: 1