Skip to content

Commit

Permalink
Merge pull request #9 from awesto/releases/1.0
Browse files Browse the repository at this point in the history
Releases/1.0
  • Loading branch information
jrief authored May 4, 2019
2 parents d1db892 + 356965d commit 7f4614a
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 60 deletions.
28 changes: 11 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
# REST based PayPal Payment Provider Integration for django-shop

This integrates the PayPal for django-shop version 0.9 and above.
This integrates PayPal for django-shop version 1.0 and above.

## Installation

for django-shop version 0.10.x:
for django-shop version 1.0.x:

```
pip install djangoshop-paypal==0.1.4
```

for django-shop version 0.10.x:

```
pip install djangoshop-paypal==0.2.0
pip install djangoshop-paypal<1.1
```

## Configuration
Expand All @@ -29,8 +23,9 @@ For a testing account add them as:
SHOP_PAYPAL = {
'API_ENDPOINT': 'https://api.sandbox.paypal.com',
'MODE': 'sandbox',
'CLIENT_ID': '<client-id-as-delivered-by-PayPal>',
'CLIENT_SECRET': '<client-secret-as-delivered-by-PayPal>',
'CLIENT_ID': '<client-id-as-provided-by-PayPal>',
'CLIENT_SECRET': '<client-secret-as-provided-by-PayPal>',
'PURCHASE_DESCRIPTION': "Thanks for purchasing at My Shop",
}
```

Expand All @@ -40,8 +35,9 @@ and for production:
SHOP_PAYPAL = {
'API_ENDPOINT': 'https://api.paypal.com',
'MODE': 'live',
'CLIENT_ID': '<client-id-as-delivered-by-PayPal>',
'CLIENT_SECRET': '<client-secret-as-delivered-by-PayPal>',
'CLIENT_ID': '<client-id-as-provided-by-PayPal>',
'CLIENT_SECRET': '<client-secret-as-provided-by-PayPal>',
'PURCHASE_DESCRIPTION': "Thanks for purchasing at My Shop",
}
```

Expand All @@ -51,9 +47,7 @@ Add ``'shop_paypal.payment.OrderWorkflowMixin'`` to the list of ``SHOP_ORDER_WOR

When rendering the payment method form, "PayPal" shall appear in the list of possible payments.

Successful payments are redirected onto the CMS page with the ID ``shop-order-last``. If no such
CMS page exists, the URL which resolves to ``shop-order-last`` is returned.
Successful payments are redirected onto the just created order detail page.

If a payment was rejected by PayPal, **djangoshop-paypal** redirects onto the CMS page with the ID
``shop-cancel-payment``. If no such CMS page exists, the URL which resolves to
``shop-cancel-payment`` is returned.
``shop-cancel-payment``, so make sure that such a page exists.
14 changes: 6 additions & 8 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@
from __future__ import unicode_literals
from setuptools import setup, find_packages
import shop_paypal
try:
from pypandoc import convert
except ImportError:
def convert(filename, fmt):
with open(filename) as fd:
return fd.read()

with open('README.md', 'r') as fh:
long_description = fh.read()

CLASSIFIERS = [
'Environment :: Web Environment',
Expand All @@ -27,13 +24,14 @@ def convert(filename, fmt):
name='djangoshop-paypal',
version=shop_paypal.__version__,
description="PayPal Payment Provider Integration for django-shop",
long_description=convert('README.md', 'rst'),
long_description=long_description,
long_description_content_type='text/markdown',
url='https://github.com/jrief/djangoshop-paypal',
license='MIT License',
platforms=['OS Independent'],
classifiers=CLASSIFIERS,
install_requires=[
'paypalrestsdk>=1.12.0',
'paypalrestsdk>=1.13.0',
'requests>=2.14.1',
],
packages=find_packages(),
Expand Down
2 changes: 1 addition & 1 deletion shop_paypal/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = '0.2.1'
__version__ = '1.0.0'
3 changes: 1 addition & 2 deletions shop_paypal/modifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
from __future__ import unicode_literals

from django.utils.translation import ugettext_lazy as _
from shop.modifiers.base import PaymentModifier as PaymentModifierBase
from shop.payment.modifiers import PaymentModifier as PaymentModifierBase
from .payment import PayPalPayment


class PaymentModifier(PaymentModifierBase):
"""
Cart modifier which handles payment through PayPal.
"""
identifier = PayPalPayment.namespace
payment_provider = PayPalPayment()
commision_percentage = None

Expand Down
66 changes: 34 additions & 32 deletions shop_paypal/payment.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,21 @@
import paypalrestsdk
import warnings
from decimal import Decimal
from distutils.version import LooseVersion

from django.conf import settings
from django.conf.urls import url
from django.core.serializers.json import DjangoJSONEncoder
from django.core.urlresolvers import resolve, reverse
from django.core.exceptions import ImproperlyConfigured
from django.http.response import HttpResponseRedirect, HttpResponseBadRequest
from django.urls import NoReverseMatch
from django.utils.translation import ugettext_lazy as _
from cms.models import Page

from shop import __version__ as SHOP_VERSION
from shop.models.cart import CartModel
from shop.models.order import BaseOrder, OrderModel, OrderPayment
from shop.money import MoneyMaker
from shop.payment.base import PaymentProvider
from shop.payment.providers import PaymentProvider
from django_fsm import transition


Expand All @@ -37,13 +36,13 @@ def get_urls(self):
]

@classmethod
def get_auth_token(cls):
api = paypalrestsdk.set_config(
mode=settings.SHOP_PAYPAL['MODE'],
client_id=settings.SHOP_PAYPAL['CLIENT_ID'],
client_secret=settings.SHOP_PAYPAL['CLIENT_SECRET'])
auth_token_hash = api.get_token_hash()
return auth_token_hash
def get_paypal_api(cls):
api = paypalrestsdk.Api({
'mode': settings.SHOP_PAYPAL['MODE'],
'client_id': settings.SHOP_PAYPAL['CLIENT_ID'],
'client_secret': settings.SHOP_PAYPAL['CLIENT_SECRET'],
})
return api

def get_payment_request(self, cart, request):
"""
Expand All @@ -52,9 +51,16 @@ def get_payment_request(self, cart, request):
shop_ns = resolve(request.path).namespace
return_url = reverse('{}:{}:return'.format(shop_ns, self.namespace))
cancel_url = reverse('{}:{}:cancel'.format(shop_ns, self.namespace))
cart = CartModel.objects.get_from_request(request)
cart.update(request) # to calculate the total
auth_token_hash = self.get_auth_token()
paypal_api = self.get_paypal_api()
auth_token_hash = paypal_api.get_token_hash()
items = []
for cart_item in cart.items.all():
items.append({
'name': cart_item.product.product_name,
'quantity': str(int(cart_item.quantity)),
'price': str(cart_item.product.unit_price.as_decimal()),
'currency': cart_item.product.unit_price.currency,
})
payload = {
'url': '{API_ENDPOINT}/v1/payments/payment'.format(**settings.SHOP_PAYPAL),
'method': 'POST',
Expand All @@ -72,10 +78,14 @@ def get_payment_request(self, cart, request):
'payment_method': 'paypal',
},
'transactions': [{
'item_list': {
'items': items,
},
'amount': {
'total': cart.total.as_decimal(),
'total': str(cart.total.as_decimal()),
'currency': cart.total.currency,
}
},
'description': settings.SHOP_PAYPAL['PURCHASE_DESCRIPTION']
}]
}
}
Expand Down Expand Up @@ -103,28 +113,20 @@ def return_view(cls, request):
warnings.warn("Request for PayPal return_url is invalid: {}".format(err.message))
return HttpResponseBadRequest("Invalid Payment Request")
try:
cls.get_auth_token()
payment = paypalrestsdk.Payment.find(payment_id)
paypal_api = cls.get_paypal_api()
payment = paypalrestsdk.Payment.find(payment_id, api=paypal_api)
approved = payment.execute(params)
except Exception as err:
warnings.warn("An internal error occurred on the upstream server: {}".format(err.message))
warnings.warn("An internal error occurred on the upstream server: {}".format(err))
return cls.cancel_view(request)

if approved:
if LooseVersion(SHOP_VERSION) < LooseVersion('0.11'):
cart = CartModel.objects.get_from_request(request)
order = OrderModel.objects.create_from_cart(cart, request)
order.add_paypal_payment(payment.to_dict())
order.save()
else:
cart = CartModel.objects.get_from_request(request)
order = OrderModel.objects.create_from_cart(cart, request)
order.populate_from_cart(cart, request)
order.add_paypal_payment(payment.to_dict())
order.save()

thank_you_url = OrderModel.objects.get_latest_url()
return HttpResponseRedirect(thank_you_url)
cart = CartModel.objects.get_from_request(request)
order = OrderModel.objects.create_from_cart(cart, request)
order.populate_from_cart(cart, request)
order.add_paypal_payment(payment.to_dict())
order.save(with_notification=True)
return HttpResponseRedirect(order.get_absolute_url())
return cls.cancel_view(request)

@classmethod
Expand Down

0 comments on commit 7f4614a

Please sign in to comment.