2022-04-01 11:11:50 -06:00

167 lines
6.9 KiB
Python

import os
import sys
import json
import logging
from paypalcheckoutsdk.core import PayPalHttpClient, SandboxEnvironment
from paypalcheckoutsdk.orders import OrdersCreateRequest, OrdersCaptureRequest
from paypalhttp.serializers.json_serializer import Json
from django.conf import settings
from django.contrib.sites.models import Site
from django.urls import reverse_lazy
logger = logging.getLogger(__name__)
class PayPalClient:
def __init__(self):
self.client_id = settings.PAYPAL_CLIENT_ID
self.client_secret = settings.PAYPAL_SECRET_ID
self.site_domain = Site.objects.get_current().domain
self.site_name = Site.objects.get_current().name
"""Setting up and Returns PayPal SDK environment with PayPal Access credentials.
For demo purpose, we are using SandboxEnvironment. In production this will be
LiveEnvironment."""
self.environment = SandboxEnvironment(client_id=self.client_id, client_secret=self.client_secret)
""" Returns PayPal HTTP client instance with environment which has access
credentials context. This can be used invoke PayPal API's provided the
credentials have the access to do so. """
self.client = PayPalHttpClient(self.environment)
def object_to_json(self, json_data):
"""
Function to print all json data in an organized readable manner
"""
result = {}
if sys.version_info[0] < 3:
itr = json_data.__dict__.iteritems()
else:
itr = json_data.__dict__.items()
for key,value in itr:
# Skip internal attributes.
if key.startswith("__") or key.startswith("_"):
continue
result[key] = self.array_to_json_array(value) if isinstance(value, list) else\
self.object_to_json(value) if not self.is_primittive(value) else\
value
return result
def array_to_json_array(self, json_array):
result =[]
if isinstance(json_array, list):
for item in json_array:
result.append(self.object_to_json(item) if not self.is_primittive(item) \
else self.array_to_json_array(item) if isinstance(item, list) else item)
return result
def is_primittive(self, data):
return isinstance(data, str) or isinstance(data, unicode) or isinstance(data, int)
class CreateOrder(PayPalClient):
"""Setting up the JSON request body for creating the Order. The Intent in the
request body should be set as "CAPTURE" for capture intent flow."""
def build_request_body(self, params):
"""Method to create body with CAPTURE intent"""
processed_items = [{
# Shows within upper-right dropdown during payment approval
'name': f'{item["product"]}',
# Item details will also be in the completed paypal.com transaction view
'description': 'Coffee',
'unit_amount': {
'currency_code': 'USD',
'value': f'{item["price"]}'
},
'quantity': f'{item["quantity"]}'
} for item in params['items']]
request_body = {
"intent": "CAPTURE",
"application_context": {
"return_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-done')}",
"cancel_url": f"https://{self.site_domain}{reverse_lazy('storefront:payment-canceled')}",
"brand_name": f"{self.site_name}",
# "landing_page": "BILLING",
# "shipping_preference": "SET_PROVIDED_ADDRESS",
# "user_action": "CONTINUE"
},
"purchase_units": [
{
# "reference_id": "PUHF",
"description": "Coffee",
# "custom_id": "CUST-HighFashions",
# "soft_descriptor": "HighFashions",
"amount": {
"currency_code": "USD",
"value": params['total_price'],
"breakdown": {
"item_total": {
"currency_code": "USD",
"value": params['item_total']
},
"shipping": {
"currency_code": "USD",
"value": params['shipping_price']
},
"tax_total": {
"currency_code": "USD",
"value": params['tax_total']
},
"discount": {
"currency_code": "USD",
"value": params['discount']
}
}
},
"items": processed_items,
"shipping": {
"method": params['shipping_method'],
"address": params['shipping_address']
}
}
]
}
logger.info(f'\nRequest body: {request_body}\n')
return request_body
""" This is the sample function which can be sued to create an order. It uses the
JSON body returned by buildRequestBody() to create an new Order."""
def create_order(self, params, debug=False):
request = OrdersCreateRequest()
request.headers['prefer'] = 'return=representation'
request.request_body(self.build_request_body(params))
response = self.client.execute(request)
if debug:
logger.info(f'\nStatus Code: {response.status_code}', )
logger.info(f'\nStatus: {response.result.status}', )
logger.info(f'\nOrder ID: {response.result.id}', )
logger.info(f'\nIntent: {response.result.intent}', )
logger.info(f"\njson_data: {response.result}")
return response
class CaptureOrder(PayPalClient):
"""this is the sample function performing payment capture on the order. Approved Order id should be passed as an argument to this function"""
def capture_order(self, order_id, debug=False):
"""Method to capture order using order_id"""
request = OrdersCaptureRequest(order_id)
response = self.client.execute(request)
data = response.result.__dict__['_dict']
data['redirect_urls'] = {
'return_url': f"https://{self.site_domain}{reverse_lazy('storefront:payment-done')}",
'cancel_url': f"https://{self.site_domain}{reverse_lazy('storefront:payment-canceled')}"
}
return data