182 lines
6.7 KiB
Python
182 lines
6.7 KiB
Python
import os
|
|
import sys
|
|
import json
|
|
import logging
|
|
|
|
from paypalcheckoutsdk.core import (
|
|
PayPalHttpClient, SandboxEnvironment, LiveEnvironment
|
|
)
|
|
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
|
|
|
|
from core import CoffeeGrind
|
|
|
|
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."""
|
|
if settings.PAYPAL_ENVIRONMENT == "LIVE":
|
|
self.environment = LiveEnvironment(
|
|
client_id=self.client_id, client_secret=self.client_secret
|
|
)
|
|
else:
|
|
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"""
|
|
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": str(params["total_price"]),
|
|
"breakdown": {
|
|
"item_total": {
|
|
"currency_code": "USD",
|
|
"value": str(params["item_total"]),
|
|
},
|
|
"shipping": {
|
|
"currency_code": "USD",
|
|
"value": str(params["shipping_price"]),
|
|
},
|
|
"tax_total": {
|
|
"currency_code": "USD",
|
|
"value": params["tax_total"],
|
|
},
|
|
"discount": {
|
|
"currency_code": "USD",
|
|
"value": str(params["discount"]),
|
|
},
|
|
},
|
|
},
|
|
"items": [dict(item) for item in params['items']],
|
|
"shipping": {
|
|
"method": params["shipping_method"],
|
|
"address": params["shipping_address"],
|
|
},
|
|
}
|
|
],
|
|
}
|
|
|
|
logger.debug(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.debug(
|
|
f"\nStatus Code: {response.status_code}",
|
|
)
|
|
logger.debug(
|
|
f"\nStatus: {response.result.status}",
|
|
)
|
|
logger.debug(
|
|
f"\nOrder ID: {response.result.id}",
|
|
)
|
|
logger.debug(
|
|
f"\nIntent: {response.result.intent}",
|
|
)
|
|
logger.debug(f"\njson_data: {response.result}")
|
|
|
|
return response
|
|
|
|
|
|
class CaptureOrder(PayPalClient):
|
|
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
|