예제 #1
0
def processing_payment(request, assignment_id):
    assignment = get_object_or_404(Assignment, id=assignment_id)
    if request.method == 'POST':
        environment = LiveEnvironment(client_id=settings.PAYPAL_CLIENT_ID,
                                      client_secret=settings.PAYPAL_SECRET_ID)
        client = PayPalHttpClient(environment)
        create_order = OrdersCreateRequest()
        create_order.request_body({
            "intent":
            "CAPTURE",
            "purchase_units": [{
                "amount": {
                    "currency_code": "USD",
                    "value": assignment.price,
                    "breakdown": {
                        "item_total": {
                            "currency_code": "USD",
                            "value": assignment.price
                        }
                    },
                },
            }]
        })

        response = client.execute(create_order)
        data = response.result.__dict__['_dict']
        return JsonResponse(data)
예제 #2
0
class PayPalHandler:
    def __init__(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret
        self.create_environment()
        self.create_client()

    def create_environment(self):
        '''
        Create sandbox environment for PayPal
        '''
        self.env = SandboxEnvironment(
            client_id=self.client_id,
            client_secret=self.client_secret
        )

    def create_client(self):
        '''
        Create the client
        '''
        self.client = PayPalHttpClient(self.env)

    def capture_order(self, order_id, debug=True):
        request = OrdersCaptureRequest(order_id)
        response = self.client.execute(request)

        if debug:
            print("Status Code: ", response.status_code)
            print("Status: ", response.result.status)
            print("Order ID: ", response.result.id)
            print("Links: ")

            for link in response.result.links:
                print('\t{}: {}\tCall Type: {}'.format(link.rel, link.href, link.method))

            print("Capture Ids:")
            for purchase_unit in response.result.purchase_units:
                for capture in purchase_unit.payments.captures:
                    print("\t", capture.id)
        
        return self.parse_response(response)

    def parse_response(self, response):
        return {
            "status_code": response.status_code,
            "status": response.result.status,
            "order_id": response.result.id,
            "links": [ { "rel": link.rel, "href": link.href, "method": link.method } for link in response.result.links ],
            "reference_id": response.result.purchase_units[0].reference_id,

            "buyer": {
                "email": response.result.payer.email_address,
            }
        }

    def is_completed(self, response):
        return response["status"] == "COMPLETED"
예제 #3
0
def create_paypal_order(session, donation):
    paypalSettings = getPayPalSettings()
    client = PayPalHttpClient(paypalSettings.environment)

    req = OrdersCreateRequest()
    # set dictionary object in session['extra_test_headers'] in TestCases
    if session.get('extra_test_headers', None) and donation.is_test:
        for key, value in session.get('extra_test_headers').items():
            req.headers[key] = value
    req.prefer('return=representation')
    req.request_body(build_onetime_request_body(donation))
    return client.execute(req)
예제 #4
0
def pago(request):
    # Creating Access Token for Sandbox
    client_id = "AWKxRtjpmHR9Jd8n8fMGO77lqcIw7fFHML19xSzd1Scfv4Mk-XGwnjBYJIkaRaFa_y2LC2PXBulTMPFK"
    client_secret = "EGlVhQYGDzop2HftvmEqh726ChUjz4e7x_Ai4Hp900iA8troRX5feiS6ThlfB-HSVwzKNdHW2W3BzCyf"
    # Creating an environment
    environment = SandboxEnvironment(client_id=client_id,
                                     client_secret=client_secret)
    client = PayPalHttpClient(environment)
    # Construct a request object and set desired parameters
    # Here, OrdersCreateRequest() creates a POST request to /v2/checkout/orders
    requestPaypal = OrdersCreateRequest()
    sesion_id = request.session.session_key
    registro = Ventas_por_enviar.objects.filter(sesion=sesion_id)
    posicion = (len(registro))
    total = registro[posicion - 1].total
    total_stripe = float(total)
    total_stripe = total_stripe * 100
    requestPaypal.prefer('return=representation')
    requestPaypal.request_body({
        "intent":
        "CAPTURE",
        "purchase_units": [{
            "amount": {
                "currency_code": 'MXN',
                "value": float(total),
            }
        }],
        "application_context": {
            "return_url": "http://127.0.0.1:8000/checkout/exitoso",
            "cancel_url": "http://127.0.0.1:8000/checkout/cancelado",
            "brand_name": "Joyapan"
        }
    })
    try:
        # Call API with your client and get a response for your call
        response = client.execute(requestPaypal)
        if response.result.status == 'CREATED':
            approval_url = str(response.result.links[1].href)
            print(approval_url)


            return render(request, 'checkout/pago.html',{#aqui es donde esta el boton 
            'approval_url':approval_url,'STRIPE_PUBLISHABLE_KEY':settings.STRIPE_PUBLISHABLE_KEY,'total':total,'total_stripe':total_stripe,
            })

    except IOError as ioe:
        print(ioe)
        if isinstance(ioe, HttpError):
            # Something went wrong server-side
            return render(request, 'checkout/pago_cancelado.html')
예제 #5
0
def pago_exitoso(request):
    # Creating Access Token for Sandbox
    client_id = "AWKxRtjpmHR9Jd8n8fMGO77lqcIw7fFHML19xSzd1Scfv4Mk-XGwnjBYJIkaRaFa_y2LC2PXBulTMPFK"
    client_secret = "EGlVhQYGDzop2HftvmEqh726ChUjz4e7x_Ai4Hp900iA8troRX5feiS6ThlfB-HSVwzKNdHW2W3BzCyf"
    # Creating an environment
    environment = SandboxEnvironment(client_id=client_id,
                                     client_secret=client_secret)
    client = PayPalHttpClient(environment)
    ordenId = request.GET.get('token')
    payerId = request.GET.get('PayerID')

    requestPaypal = OrdersCaptureRequest(ordenId)
    print("RequestPaypal")
    print(requestPaypal)
    requestPaypal.prefer('return=representation')
    try:
        # Call API with your client and get a response for your call
        response = client.execute(requestPaypal)
        # If call returns body in response, you can get the deserialized version from the result attribute of the response
        print("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")

        order = response.result.id
        sesion_id = request.session.session_key
        registro = Ventas_por_enviar.objects.filter(sesion=sesion_id)
        posicion = (len(registro))
        registro[posicion - 1].autorizacion = order
        registro[posicion - 1].verificacion = payerId
        diccionario = {
            'nombre': registro[posicion - 1].nombre,
            'email': registro[posicion - 1].email,
        }
        registro[posicion - 1].save()
        envio_email_confirmacion(diccionario)

    except IOError as ioe:
        if isinstance(ioe, HttpError):
            # Something went wrong server-side
            print("Algo salio mal :c")
            print(ioe.status_code)
            print(ioe.headers)
            print(ioe)
            return render(request, 'checkout/pago_cancelado.html')
        else:
            # Something went wrong client side
            print(ioe)
        return render(request, 'checkout/pago_cancelado.html')

    return render(request, 'checkout/pago_exitoso.html')
예제 #6
0
def capture(request, order_id, assignment_id):
    assignment = get_object_or_404(Assignment, id=assignment_id)
    if request.method == "POST":
        capture_order = OrdersCaptureRequest(order_id)
        Order.objects.create(token=order_id,
                             total=assignment.price,
                             emailAddress=assignment.creator.email,
                             assignment=assignment,
                             paid=True,
                             client=assignment.creator,
                             writer=assignment.writer,
                             support=assignment.support)
        environment = LiveEnvironment(client_id=settings.PAYPAL_CLIENT_ID,
                                      client_secret=settings.PAYPAL_SECRET_ID)
        client = PayPalHttpClient(environment)

        response = client.execute(capture_order)
        data = response.result.__dict__['_dict']

        return JsonResponse(data)
    else:
        return JsonResponse({'details': "invalid request"})
예제 #7
0
def capture_paypal_order(donation, order_id):
    """Method to capture order using order_id"""
    paypalSettings = getPayPalSettings()
    client = PayPalHttpClient(paypalSettings.environment)

    req = OrdersCaptureRequest(order_id)
    _debug('PayPal: Capture Order')
    try:
        response = client.execute(req)
    except IOError as ioe:
        fail_reason = str(ioe)
        if isinstance(ioe, HttpError):
            # Something went wrong server-side
            httpError = json.loads(ioe.message)
            if 'details' in httpError and len(httpError['details']) > 0:
                fail_reason = process_capture_failure(
                    donation, httpError['details'][0]['issue'],
                    httpError['details'][0]['description'])
        # update donation status to failed
        donation.payment_status = STATUS_FAILED
        donation.save()
        raise IOError(fail_reason)
    return response.result
예제 #8
0
def create_checkout_session(request):
    data = json.loads(request.body)

    # Coupon 

    coupon_code = data['coupon_code']
    coupon_value = 0

    if coupon_code != '':
        coupon = Coupon.objects.get(code=coupon_code)

        if coupon.can_use():
            coupon_value = coupon.value
            coupon.use()

    #

    cart = Cart(request)
    items = []
    
    for item in cart:
        product = item['product']

        price = int(product.price * 100)

        if coupon_value > 0:
            price = int(price * (int(coupon_value) / 100))

        obj = {
            'price_data': {
                'currency': 'usd',
                'product_data': {
                    'name': product.title
                },
                'unit_amount': price
            },
            'quantity': item['quantity']
        }

        items.append(obj)

    gateway = data['gateway']
    session = ''
    order_id = ''
    payment_intent = ''
    
    if gateway == 'stripe':
        stripe.api_key = settings.STRIPE_API_KEY_HIDDEN
        session = stripe.checkout.Session.create(
            payment_method_types=['card'],
            line_items=items,
            mode='payment',
            success_url='http://127.0.0.1:8000/cart/success/',
            cancel_url='http://127.0.0.1:8000/cart/'
        )
        payment_intent = session.payment_intent

    #
    # Create order

    orderid = checkout(request, data['first_name'], data['last_name'], data['email'], data['address'], data['zipcode'], data['place'], data['phone'])

    total_price = 0.00

    for item in cart:
        product = item['product']
        total_price = total_price + (float(product.price) * int(item['quantity']))

    if coupon_value > 0:
        total_price = total_price * (coupon_value / 100)
    
    if gateway == 'razorpay':
        order_amount = total_price * 100
        order_currency = 'INR'
        client = razorpay.Client(auth=(settings.RAZORPAY_API_KEY_PUBLISHABLE, settings.RAZORPAY_API_KEY_HIDDEN))
        data = {
            'amount': order_amount,
            'currency': order_currency
        }

        payment_intent = client.order.create(data=data)
    
    # PayPal

    if gateway == 'paypal':
        order_id = data['order_id']
        environment = SandboxEnvironment(client_id=settings.PAYPAL_API_KEY_PUBLISHABLE, client_secret=settings.PAYPAL_API_KEY_HIDDEN)
        client = PayPalHttpClient(environment)

        request = OrdersCaptureRequest(order_id)
        response = client.execute(request)

        order = Order.objects.get(pk=orderid)
        order.paid_amount = total_price
        order.used_coupon = coupon_code

        if response.result.status == 'COMPLETED':
            order.paid = True
            order.payment_intent = order_id
            order.save()

            decrement_product_quantity(order)
            send_order_confirmation(order)
        else:
            order.paid = False
            order.save()
    else:
        order = Order.objects.get(pk=orderid)
        if gateway == 'razorpay':
            order.payment_intent = payment_intent['id']
        else:
            order.payment_intent = payment_intent
        order.paid_amount = total_price
        order.used_coupon = coupon_code
        order.save()

    #

    return JsonResponse({'session': session, 'order': payment_intent})
예제 #9
0
class PaymentProcessor:
    client = None

    def __init__(self):
        credentials = {
            'client_id': settings.PAYPAL_CLIENT_ID,
            'client_secret': settings.PAYPAL_CLIENT_SECRET,
        }

        if getattr(settings, 'PAYPAL_SANDBOX_MODE', True):
            environment = SandboxEnvironment(**credentials)
        else:
            environment = LiveEnvironment(**credentials)

        self.client = PayPalHttpClient(environment)

    def build_order_create_request_body(
        self,
        basket,
        currency,
        return_url,
        cancel_url,
        order_total,
        address=None,
        shipping_charge=None,
        intent=None,
    ):
        application_context = {
            'return_url':
            return_url,
            'cancel_url':
            cancel_url,
            'landing_page':
            get_landing_page(),
            'shipping_preference':
            'SET_PROVIDED_ADDRESS'
            if address is not None else 'NO_SHIPPING',  # TODO: ???
            'user_action':
            'PAY_NOW' if buyer_pays_on_paypal() else 'CONTINUE',
        }

        if getattr(settings, 'PAYPAL_BRAND_NAME', None) is not None:
            application_context['brand_name'] = settings.PAYPAL_BRAND_NAME

        breakdown = {
            'item_total': {
                'currency_code': currency,
                'value': format_amount(basket.total_incl_tax_excl_discounts),
            },
            'discount': {
                'currency_code':
                currency,
                'value':
                format_amount(
                    sum([
                        discount['discount']
                        for discount in basket.offer_discounts +
                        basket.voucher_discounts
                    ], D(0))),
            },
            'shipping_discount': {
                'currency_code':
                currency,
                'value':
                format_amount(
                    sum([
                        discount['discount']
                        for discount in basket.shipping_discounts
                    ], D(0))),
            }
        }

        if shipping_charge is not None:
            breakdown['shipping'] = {
                'currency_code': currency,
                'value': format_amount(shipping_charge),
            }

        purchase_unit = {
            'amount': {
                'currency_code': currency,
                'value': format_amount(order_total),
                'breakdown': breakdown,
            }
        }

        items = []
        for line in basket.all_lines():
            product = line.product
            item = {
                'name':
                product.get_title(),
                'description':
                format_description(product.description),
                'sku':
                product.upc if product.upc else '',
                'unit_amount': {
                    'currency_code': currency,
                    'value': format_amount(line.unit_price_incl_tax)
                },
                'quantity':
                line.quantity,
                'category':
                'PHYSICAL_GOODS'
                if product.is_shipping_required else 'DIGITAL_GOODS'
            }
            items.append(item)

        purchase_unit['items'] = items

        if address is not None:
            purchase_unit['shipping'] = {
                'name': {
                    'full_name': address.name
                },
                'address': {
                    'address_line_1': address.line1,
                    'address_line_2': address.line2,
                    'admin_area_2': address.line4,
                    'admin_area_1': address.state,
                    'postal_code': address.postcode,
                    'country_code': address.country.iso_3166_1_a2
                }
            }

        body = {
            'intent': intent,
            'application_context': application_context,
            'purchase_units': [purchase_unit]
        }
        return body

    def build_refund_order_request_body(self, amount, currency):
        return {
            'amount': {
                'value': format_amount(amount),
                'currency_code': currency
            }
        }

    def create_order(
        self,
        basket,
        currency,
        return_url,
        cancel_url,
        order_total,
        address=None,
        shipping_charge=None,
        intent=None,
        preferred_response='minimal',
    ):
        request = OrdersCreateRequest()
        request.prefer(f'return={preferred_response}')
        request.request_body(
            self.build_order_create_request_body(
                basket=basket,
                currency=currency,
                return_url=return_url,
                cancel_url=cancel_url,
                order_total=order_total,
                intent=intent,
                address=address,
                shipping_charge=shipping_charge,
            ))
        response = self.client.execute(request)
        return response.result

    def get_order(self, token):
        request = OrdersGetRequest(token)
        response = self.client.execute(request)
        return response.result

    def get_authorize_request_body(self):
        return {}

    def authorize_order(self, order_id, preferred_response='minimal'):
        request = OrdersAuthorizeRequest(order_id)
        request.prefer(f'return={preferred_response}')
        request.request_body(self.get_authorize_request_body())
        response = self.client.execute(request)
        return response.result

    def void_authorized_order(self, authorization_id):
        request = AuthorizationsVoidRequest(authorization_id)
        self.client.execute(request)

    def refund_order(self,
                     capture_id,
                     amount,
                     currency,
                     preferred_response='minimal'):
        request = CapturesRefundRequest(capture_id)
        request.prefer(f'return={preferred_response}')
        request.request_body(
            self.build_refund_order_request_body(amount, currency))
        response = self.client.execute(request)
        return response.result

    def capture_order(self, token, intent, preferred_response='minimal'):
        capture_request = INTENT_REQUEST_MAPPING[intent]
        request = capture_request(token)
        request.prefer(f'return={preferred_response}')
        response = self.client.execute(request)
        return response.result
예제 #10
0
class PayPalHttpClientTest(PayPalTestHarness):
    def setUp(self):
        self.client = PayPalHttpClient(self.environment())

    @responses.activate
    def testPayPalHttpClient_execute_fetchesAccessTokenIfNone(self):
        request = SimpleRequest("/", "POST")
        self.stub_request_with_response(request)
        self.stubaccesstokenrequest()

        self.client.execute(request)

        self.assertEqual(2, len(responses.calls))

        accesstokenrequest = responses.calls[0].request
        self.assertEqual(self.environment().base_url + "/v1/oauth2/token",
                         accesstokenrequest.url)
        self.assertEqual("application/x-www-form-urlencoded",
                         accesstokenrequest.headers["Content-Type"])

        expectedauthheader = "Basic {0}".format(
            base64.b64encode(("{0}:{1}".format(
                self.environment().client_id,
                self.environment().client_secret)).encode()).decode())
        self.assertEqual(expectedauthheader,
                         accesstokenrequest.headers["Authorization"])
        self.assertEqual("grant_type=client_credentials",
                         accesstokenrequest.body)

    @responses.activate
    def testPayPalHttpClient_execute_fetchesAccessTokenIfExpired(self):
        request = SimpleRequest("/", "POST")
        self.stub_request_with_response(request)

        self.client._access_token = self.simpleaccesstoken()
        self.client._access_token.expires_in = 0

        self.stubaccesstokenrequest()

        self.client.execute(request)

        self.assertEqual(2, len(responses.calls))

        accesstokenrequest = responses.calls[0].request
        self.assertEqual(self.environment().base_url + "/v1/oauth2/token",
                         accesstokenrequest.url)

    @responses.activate
    def testPayPalHttpClient_execute_doesNotFetchAccessTokenIfAuthorizationHeaderAlreadyPresent(
            self):
        request = SimpleRequest("/", "POST")
        request.headers["Authorization"] = "custom-header-value"
        self.stub_request_with_response(request)

        self.client.execute(request)

        self.assertEqual(1, len(responses.calls))

        actualRequest = responses.calls[0].request
        self.assertEqual(self.environment().base_url + "/", actualRequest.url)
        self.assertEqual("custom-header-value",
                         actualRequest.headers["Authorization"])

    @responses.activate
    def testPayPalHttpClient_withRefreshToken_fetchesAccessTokenWithRefreshToken(
            self):
        request = SimpleRequest("/", "POST")
        self.stub_request_with_response(request)

        self.client = PayPalHttpClient(self.environment(),
                                       refresh_token="refresh-token")

        self.stubaccesstokenrequest(refresh_token="refresh-token")

        self.client.execute(request)

        self.assertEqual(2, len(responses.calls))

        accesstokenrequest = responses.calls[0].request
        self.assertEqual(self.environment().base_url + "/v1/oauth2/token",
                         accesstokenrequest.url)
        self.assertEqual("application/x-www-form-urlencoded",
                         accesstokenrequest.headers["Content-Type"])

        expectedauthheader = "Basic {0}".format(
            base64.b64encode(("{0}:{1}".format(
                self.environment().client_id,
                self.environment().client_secret)).encode()).decode())
        self.assertEqual(expectedauthheader,
                         accesstokenrequest.headers["Authorization"])
        self.assertTrue("grant_type=refresh_token" in accesstokenrequest.body)
        self.assertTrue(
            "refresh_token=refresh-token" in accesstokenrequest.body)

    @responses.activate
    def testPayPalHttpClient_execute_setsCommonHeaders_signsRequest(self):
        self.client._access_token = self.simpleaccesstoken()

        request = SimpleRequest("/", "POST")
        self.stub_request_with_response(request)

        self.client.execute(request)

        self.assertEqual(len(responses.calls), 1)

        actualrequest = responses.calls[0].request
        self.assertEqual(actualrequest.headers["Accept-Encoding"], "gzip")
        self.assertEqual(actualrequest.headers["Authorization"],
                         "Bearer sample-access-token")

    @responses.activate
    def testPayPalHttpClient_execute_refreshTokenRequest(self):
        refresh_token_request = RefreshTokenRequest(self.environment(),
                                                    "auth-code")
        self.stub_request_with_response(refresh_token_request)

        self.client.execute(refresh_token_request)

        self.assertEqual(len(responses.calls), 1)

        actualrequest = responses.calls[0].request
        expectedauthheader = "Basic {0}".format(
            base64.b64encode(("{0}:{1}".format(
                self.environment().client_id,
                self.environment().client_secret)).encode()).decode())
        self.assertEqual(
            actualrequest.url,
            self.environment().base_url +
            "/v1/identity/openidconnect/tokenservice")
        self.assertEqual(actualrequest.headers["Authorization"],
                         expectedauthheader)
        self.assertEqual(actualrequest.headers["Content-Type"],
                         "application/x-www-form-urlencoded")
        self.assertTrue("grant_type=authorization_code" in actualrequest.body)
        self.assertTrue("code=auth-code" in actualrequest.body)
예제 #11
0
class PaypalClient(PaymentSystemClient):
    """Клиент платёжной системы PayPal.

    Содержит методы для инициализации сессии и обработки платежей в виде PayPal Checkout -
    выписки, захвата, верификации и завершения Checkout."""
    _link_pattern = PayPalStrings.LINK_PATTERN.value

    def __init__(self) -> None:
        """Инициализирует сессию работы с системой PayPal."""

        # Creating an environment
        environment = SandboxEnvironment(client_id=PAYPAL_CLIENT_ID, client_secret=PAYPAL_CLIENT_SECRET)
        self.client = PayPalHttpClient(environment)
        self.process_notification = {  # todo should this be here?
            PayPalStrings.WEBHOOK_APPROVED.value: self.capture,
            PayPalStrings.WEBHOOK_COMPLETED.value: self.fulfill,
        }

    def fulfill(self, wh_data: Dict[str, Any]) -> None:
        """Завершает заказ, уведомляет клиента."""

        capture_id = wh_data['resource']['id']
        try:
            checkout = Checkout.objects.fulfill_checkout(capture_id)
            send_payment_completed(checkout)
        except UpdateCompletedCheckoutError as e:
            print(e)

    def verify(self, request: HttpRequest) -> bool:
        """Проверяет соответствие подписи вебхука на случай попытки имитации оповещения.

        Возвращает результат проверки."""

        print('RECEIVED A PAYPAL WEBHOOK')
        h = request.headers
        pprint(h)
        transmission_id = h['Paypal-Transmission-Id']
        timestamp = h['Paypal-Transmission-Time']
        actual_sig = h['Paypal-Transmission-Sig']
        webhook_id = PAYPAL_WEBHOOK_ID
        cert_url = h['Paypal-Cert-Url']
        auth_algo = h['PayPal-Auth-Algo']
        if WebhookEvent.verify(
                transmission_id,
                timestamp,
                webhook_id,
                request.body.decode('utf-8'),
                cert_url,
                actual_sig,
                auth_algo
        ):
            return True
        else:
            # raise PayPalVerificationFailed()
            return False

    def capture(self, wh_data: Dict[str, Any]) -> None:
        """Выполняет операции, связанные с захватом средств после платежа"""

        # после выполнения capture приходит второй аналогичный по типу вебхук, содержащий сведения об оплате
        # todo вообще говоря, следует здесь сверять данные по позиции и сумме, а также комиссии
        if 'payments' in wh_data['resource']['purchase_units'][0]:
            return

        checkout_id = wh_data['resource']['id']
        # if we call for a capture, then the customer has approved a payment for it
        Checkout.objects.update_checkout(checkout_id, PaypalOrderStatus.APPROVED.value)
        # Here, OrdersCaptureRequest() creates a POST request to /v2/checkout/orders
        request = OrdersCaptureRequest(checkout_id)

        # todo выделить в отдельный метод
        try:
            # Call API with your client and get a response for your call
            response = self.client.execute(request)

            # If call returns body in response, you can get the deserialized version
            # from the result attribute of the response
            order = response.result.id
            result = response.status_code
            if response.status_code == 201:
                capture_id = response.result.purchase_units[0].payments.captures[0].id
                Checkout.objects.update_capture(checkout_id, capture_id)
            print(order, result)
        except IOError as ioe:
            if isinstance(ioe, HttpError):
                # Something went wrong server-side
                print(ioe.status_code)
                print(ioe.headers)
                print(ioe)
            else:
                # Something went wrong client side
                print(ioe)

    def _initiate_payment_system_checkout(self, checkout_data: Dict[str, Any]) -> str:
        """Создаёт чекаут в системе PayPal, возвращает его id."""

        pp_capture = PaypalCheckout.Schema().load(checkout_data)

        request = OrdersCreateRequest()
        request.prefer('return=representation')
        request.request_body(pp_capture.Schema().dump(pp_capture))

        tracking_id: str = ''
        try:
            response = self.client.execute(request)
            if response.result.status == PaypalOrderStatus.CREATED.value:
                tracking_id = response.result.id
            else:
                print(response.status_code)
                for link in response.result.links:
                    logger.debug('\t{}: {}\tCall Type: {}'.format(link.rel, link.href, link.method))
                    logger.debug('Total Amount: {} {}'.format(response.result.purchase_units[0].amount.currency_code,
                                                              response.result.purchase_units[0].amount.value))
                    # If call returns body in response, you can get the deserialized version
                    # from the result attribute of the response
                    order = response.result
                    logger.debug(order)
        except IOError as ioe:
            logger.error(f'Paypal failed Checkout creation{ioe}')
            if isinstance(ioe, HttpError):
                # Something went wrong server-side
                logger.error(ioe.status_code)

        return tracking_id

    def check_out(self, order_id: int, product_id: int) -> str:
        """Создаёт Checkout по параметрам заказа, возвращает соответствующий tracking_id."""

        # todo create a builder?
        product = Product.objects.get_product_by_id(product_id)
        checkout_data = {
            'intent': PaypalIntent.CAPTURE,
            'purchase_units': [{
                'reference_id': str(order_id),
                'description': product['description'][:127],
                'amount': {
                    'currency_code': Currency.RUB,
                    'value': str(product['price'].amount),
                    'breakdown': {
                        'item_total': {
                            'currency_code': Currency.RUB,
                            'value': str(product['price'].amount),
                        }
                    },
                },
                'items': [
                    {
                        'name': product['name'],
                        'description': product['description'][:127],
                        'unit_amount': {
                            'currency_code': Currency.RUB,
                            'value': str(product['price'].amount),
                        },
                        'quantity': 1,
                        'category': PaypalGoodsCategory.PHYSICAL_GOODS,
                    }
                ]
            }],
            'application_context': {
                'shipping_preference': PaypalShippingPreference.GET_FROM_FILE,
                'user_action': PaypalUserAction.PAY_NOW,
            }
        }

        checkout_id = self._initiate_payment_system_checkout(checkout_data)
        Checkout.objects.make_checkout(PaymentSystem.PAYPAL, checkout_id, order_id)

        approve_link = self._link_pattern.format(checkout_id=checkout_id)

        return approve_link
예제 #12
0
class PayGateWay(AbstractPayFactory):
    config = {
        "__sandbox": False,
        "__client_id": "应用ID",
        "__client_secret": "商户私钥",
        "__currency_code": "USD",
        "#说明": "去掉 __ 启用对应的选项,#号为备注字典"
    }
    paypal = None

    def __init__(self, data: dict):
        super(PayGateWay, self).__init__(data)
        _env_config = {
            'client_id': self.config['client_id'],
            'client_secret': self.config['client_secret']
        }

        if self.config['sandbox']:
            environment = SandboxEnvironment(**_env_config)
        else:
            environment = LiveEnvironment(**_env_config)
        self.paypal = PayPalHttpClient(environment)

    def create_order(self, data: BaseTransactionSlip, *args,
                     **kwargs) -> BaseCreateOrderResult:
        if not isinstance(data, BaseTransactionSlip):
            raise RuntimeError("请传入一个 BaseTransactionSlip 实例")

        # params = {"out_trade_no": data.sid, "subject": data.name,
        #           "total_amount": data.price, "return_url": data.sync_url}
        request = OrdersCreateRequest()

        request.prefer('return=representation')

        request.request_body({
            "application_context": {
                "return_url": data.sync_url
            },
            "intent":
            "CAPTURE",
            ''
            "purchase_units": [{
                "invoice_id": data.sid,
                "description": data.name,
                "amount": {
                    "currency_code": self.config['currency_code'],
                    "value": data.price
                }
            }]
        })
        response = self.paypal.execute(request)
        print("创建订单数据")
        self.__print_paypal_response(response)
        for link in response.result.links:
            if link.rel == 'approve':
                return BaseCreateOrderResult(link.href)

    def notify_order(self, request, *args, **kwargs) -> BaseTransactionResult:
        print("=========收到异步通知数据=========")
        data = request.data
        print(data)
        print("=========收到异步通知数据=========")
        token = data['resource']['id']
        _sid, _pid, _status = self.__order_get_request(token)
        if _status == 'APPROVED':
            orders_capture_request = OrdersCaptureRequest(data['token'])
            capture_res = self.paypal.execute(orders_capture_request)
            print(f"确认{token}订单并收款")
            self.__print_paypal_response(capture_res)
            res_status = BaseTransactionResult.SUCCESSFULLY_VERIFIED
            result = BaseTransactionResult(_sid, _pid, res_status)
        elif _status == 'COMPLETED':
            res_status = BaseTransactionResult.SUCCESSFULLY_VERIFIED
            result = BaseTransactionResult(_sid, _pid, res_status)
        else:
            res_status = BaseTransactionResult.SIGN_VERIFICATION_FAILED
            result = BaseTransactionResult(_sid, _pid, res_status)
        return result

    def return_order(self, data: dict, *args,
                     **kwargs) -> BaseTransactionResult:
        print("=========收到同步通知数据=========")
        print(data)
        data = self.__deal_dict(data)
        print(data)
        print("=========收到同步通知数据=========")
        _sid, _pid, _status = self.__order_get_request(data['token'])
        res_status = BaseTransactionResult.UNKNOWN_PAYMENT_STATUS
        if _status == 'APPROVED':
            orders_capture_request = OrdersCaptureRequest(data['token'])
            capture_res = self.paypal.execute(orders_capture_request)
            print(f"确认{_pid}订单并收款")
            self.__print_paypal_response(capture_res)
            res_status = BaseTransactionResult.SUCCESSFULLY_VERIFIED
        result = BaseTransactionResult(_sid, _pid, res_status)
        return result

    def __order_get_request(self, token):
        request = OrdersGetRequest(token)
        response = self.paypal.execute(request)
        print(f"查询 {token} 订单数据")
        self.__print_paypal_response(response)
        _pid = response.result.id
        _purchase_units = response.result.purchase_units[0]
        _status = response.result.status
        _sid = _purchase_units['invoice_id']
        return _sid, _pid, _status

    def query_order(self, data: BaseOrderId) -> dict:
        request = OrdersGetRequest(data.pid)
        response = self.paypal.execute(request)
        json_data = PayPalResultFormatUtil.object_to_json(response.result)
        return json_data

    def cancel_order(self, data: BaseOrderId) -> BaseCancelOrder:
        return BaseCancelOrder(status=False,
                               detail={"msg": "PayPal 不支持取消未支付的订单"})

    def request_refund(self, data: BaseRequestRefund) -> bool:

        request = OrdersGetRequest(data.pid)
        response = self.paypal.execute(request)
        capture_id = response.result.purchase_units[0].payments.captures[0].id
        print(f"退款数据 {capture_id}")
        self.__print_paypal_response(response)

        request = CapturesRefundRequest(capture_id)
        request.prefer("return=representation")
        _post_data = {
            "amount": {
                "value": f"{data.price}",
                "currency_code": self.config['currency_code']
            }
        }

        request.request_body(_post_data)
        try:
            response = self.paypal.execute(request)
            return True
        except Exception as e:
            print(e)
            return False

    @staticmethod
    def __print_paypal_response(response):
        data = PayPalResultFormatUtil.object_to_json(response)
        print(json.dumps(data))

    @staticmethod
    def __deal_dict(data: dict):
        _data = {}
        for i in data:
            if isinstance(data[i], list):
                _data[i] = data[i][0]
            else:
                _data[i] = data[i]
        return _data

    @staticmethod
    def gateway_config() -> dict:
        return PayGateWay.config

    @staticmethod
    def success_http() -> HttpResponse:
        """
        When your app receives the notification message, it must respond with an HTTP 200-level status code.
        If your app responds with any other status code, PayPal tries to resend the notification message
        25 times over the course of three days.
        @return: HttpResponse 200
        """
        return HttpResponse('success', status=status.HTTP_200_OK)

    @staticmethod
    def failed_http() -> HttpResponse:
        return HttpResponse('failed', status=status.HTTP_409_CONFLICT)

    @staticmethod
    def gateway_name():
        return "PayPal"

    @staticmethod
    def gateway_description():
        return "PayPal 接口"
예제 #13
0
class PayPalClient:
    def __init__(self):
        if settings.PAYPAL_USE_SANDBOX:
            environment = SandboxEnvironment(
                client_id=settings.PAYPAL_SANDBOX_CLIENT_ID,
                client_secret=settings.PAYPAL_SANDBOX_SECRET_KEY,
            )
        else:
            environment = LiveEnvironment(
                client_id=settings.PAYPAL_LIVE_CLIENT_ID,
                client_secret=settings.PAYPAL_LIVE_SECRET_KEY,
            )

        # Returns PayPal HTTP client instance with environment that
        # has access credentials context. Use this instance to invoke
        # PayPal APIs, provided the credentials have access.
        self.client = PayPalHttpClient(environment)

    def get_order(self, order_id):
        """Query the PayPal api for information about the order. Return the
        amount of the payment (in cents) upon success or 0 otherwise

        """

        try:
            request = OrdersGetRequest(order_id)
            response = self.client.execute(request)
        except HttpError as e:
            logger.error('HttpError while fetching PayPal order: {}'.format(e))
            return '', 0

        try:
            assert response.result.intent == 'CAPTURE', 'bad payment intent'
            assert response.status_code == 200, 'bad http response code'
            assert response.result.status == 'COMPLETED', 'tx not completex'
            assert response.result.id == order_id, 'order id does not match'

            purchase = response.result.purchase_units[0]
            srb = purchase.payments.captures[0].seller_receivable_breakdown

            assert srb.paypal_fee.currency_code == 'USD', 'foreign currency'
            assert srb.net_amount.currency_code == 'USD', 'foreign currency'
            assert srb.gross_amount.currency_code == 'USD', 'foreign currency'

            parts = srb.paypal_fee.value.split('.')
            fee = int(parts[0]) * 100 + int(parts[1])
            assert fee > 0, 'invalid fee amount'

            parts = srb.net_amount.value.split('.')
            net = int(parts[0]) * 100 + int(parts[1])
            assert fee > 0, 'invalid net amount'

            parts = srb.gross_amount.value.split('.')
            gross = int(parts[0]) * 100 + int(parts[1])
            assert fee > 0, 'invalid gross amount'

            assert fee + net == gross, 'conversion error'

            payment_id = purchase.payments.captures[0].id
            assert payment_id, 'missing paypal TransactionID'

        except AssertionError as e:
            logger.error(
                'AssertionError while fetching PayPal order: {}'.format(e))
            return '', 0

        return payment_id, net, fee
예제 #14
0
    def post(self):
        try:
            data = request.get_json()
            identity = get_jwt_identity()
            validation = order.validate_razorpay_paypal_cod_order(data)
            if validation['isValid']:
                if identity['id']:
                    args = {
                        'user_id':
                        identity['id'],
                        'user_amount':
                        data['amount'],
                        'user_display_amount':
                        data['displayAmount'],
                        'order_id':
                        data['orderId'],
                        'coupon_id':
                        data['couponId'] if 'couponId' in data else None
                    }
                    # Price check

                    result = run_db_query(
                        'select _finaltotalvalue, status from '
                        ' store.fncheckprice('
                        '_user_id=>%(user_id)s, '
                        '_order_id=>%(order_id)s, '
                        '_coupon_id=>%(coupon_id)s, '
                        '_webtotalvalue=>%(user_amount)s )', args,
                        'price check call', True)

                    if result == 'error':
                        raise Exception
                    elif result['status']:
                        # Creating Access Token for Sandbox
                        client_id = secrets['LIVE_PAYPAL_ID']
                        client_secret = secrets['LIVE_PAYPAL_SECRET']

                        # Creating an environment
                        # environment = SandboxEnvironment(client_id=client_id, client_secret=client_secret)
                        environment = LiveEnvironment(
                            client_id=client_id, client_secret=client_secret)
                        client = PayPalHttpClient(environment)
                        order_request = OrdersCreateRequest()

                        order_request.prefer('return=representation')

                        order_request.request_body({
                            "intent":
                            "CAPTURE",
                            "purchase_units": [{
                                "amount": {
                                    "currency_code": "USD",
                                    "value": args['user_display_amount']
                                }
                            }],
                            "application_context": {
                                "shipping_preference": 'NO_SHIPPING'
                            }
                        })
                        try:
                            # Call API with your client and get a response for your call
                            response = client.execute(order_request)
                            if response.result and response.result.id:

                                return {
                                    'message': 'success',
                                    'data': {
                                        'orderId': response.result.id
                                    }
                                }, 200
                            else:
                                return {
                                    'message':
                                    'Error while completing payment, please retry.'
                                }, 500
                        except IOError as ioe:
                            if isinstance(ioe, HttpError):
                                # Something went wrong server-side
                                print(ioe.status_code)
                            return {
                                'message':
                                'Error while completing payment, please retry.'
                                ' If the issue still persists, try after sometime.'
                            }, 500
                    else:
                        return {
                            'message':
                            'Price changed for one or more product. Getting the latest price'
                        },
                else:
                    return {'message': 'User Auth is missing.'}, 401
            else:
                return {'message': 'Validation error, try again'}, 500

        except Exception as e:
            app.logger.debug(e)
            return {
                'message':
                'Error while completing payment, please retry.'
                ' If the issue still persists, try after sometime.'
            }, 500
예제 #15
0
    def initGatewayByReturn(request):
        # a get param named 'token' contains the order_id
        paypalSettings = getPayPalSettings()
        client = PayPalHttpClient(paypalSettings.environment)
        donation_id = None
        subscription_obj = {}
        kwargs = {}

        if request.GET.get('subscription_id', None):
            # recurring payment
            subscription_obj = getSubscriptionDetails(
                request.session, request.GET.get('subscription_id'))
            kwargs['subscription_obj'] = subscription_obj
            if 'custom_id' in subscription_obj:
                donation_id = subscription_obj['custom_id']
            else:
                raise ValueError(
                    _('Missing custom_id(donation_id) in curlPaypal-returned subscription'
                      ))
        elif request.GET.get('token', None):
            # onetime payment
            req = OrdersGetRequest(request.GET.get('token'))
            # might throw IOError
            response = client.execute(req)
            _debug('PayPal: Returns from Gateway')
            _debug('PayPal: Order status: ' + response.result.status)
            donation_id = response.result.purchase_units[0].custom_id
            kwargs['order_id'] = request.GET.get('token')
            kwargs['order_status'] = response.result.status
            if not donation_id:
                raise ValueError(
                    _("Missing donation_id in purchase_units custom_id attribute"
                      ))
        else:
            raise ValueError(_("Missing token from PayPal request"))

        try:
            donation = Donation.objects.get(pk=donation_id)

            if request.GET.get('subscription_id', None):
                # raise error if paypal_subscription_id already found in DonationPaymentMeta
                dpm = DonationPaymentMeta.objects.filter(
                    donation=donation,
                    field_key='paypal_subscription_id',
                    field_value=request.GET.get('subscription_id'))
                if len(dpm) >= 1:
                    raise ValueError(
                        _("PayPal subscription id found. Return request from PayPal is already invalid."
                          ))
                else:
                    dpm = DonationPaymentMeta(
                        donation=donation,
                        field_key='paypal_subscription_id',
                        field_value=request.GET.get('subscription_id'))
                    dpm.save()
            elif request.GET.get('token', None):
                # raise error if paypal_token already found in DonationPaymentMeta
                dpm = DonationPaymentMeta.objects.filter(
                    donation=donation,
                    field_key='paypal_token',
                    field_value=request.GET.get('token'))
                if len(dpm) >= 1:
                    raise ValueError(
                        _("PayPal token found. Return request from PayPal is already invalid."
                          ))
                else:
                    dpm = DonationPaymentMeta(
                        donation=donation,
                        field_key='paypal_token',
                        field_value=request.GET.get('token'))
                    dpm.save()
            return Factory_Paypal.initGateway(request, donation, None,
                                              **kwargs)
        except Donation.DoesNotExist:
            raise ValueError(
                _("Donation object not found by id: ") + str(donation_id))