def post(self, request, *args, **kwargs): """ Place an order. We fetch the txn details again and then proceed with oscar's standard payment details view for placing the order. """ if buyer_pays_on_paypal(): return HttpResponseBadRequest() # we don't expect any user here if we let users buy on PayPal try: self.token = request.POST['token'] except KeyError: # Probably suspicious manipulation if we get here messages.error(self.request, self.error_msg) return redirect('basket:summary') try: self.txn = fetch_transaction_details(self.token) except HttpError as e: logger.warning('Unable to fetch transaction details for token %s: %s', self.token, e.message) # Unable to fetch txn details from PayPal - we have to bail out messages.error(request, self.error_msg) return redirect('basket:summary') # Reload frozen basket which is specified in the URL basket = self.load_frozen_basket(kwargs['basket_id']) if not basket: messages.error(self.request, self.error_msg) return redirect('basket:summary') submission = self.build_submission(basket=basket) return self.submit(**submission)
def get(self, request, *args, **kwargs): """ Fetch details about the successful transaction from PayPal. We use these details to show a preview of the order with a 'submit' button to place it. The preview step can be skipped with `PAYPAL_BUYER_PAYS_ON_PAYPAL=True` inside settings. """ try: self.payer_id = request.GET['PayerID'] self.token = request.GET['token'] except KeyError: # Manipulation - redirect to basket page with warning message logger.warning('Missing GET params on success response page') messages.error(self.request, _('Unable to determine PayPal transaction details')) return redirect('basket:summary') try: self.txn = fetch_transaction_details(self.token) except HttpError as e: messages.error(self.request, e.message) logger.warning( 'Unable to fetch transaction details for token %s: %s', self.token, e.message) message = _( 'A problem occurred communicating with PayPal - please try again later' ) messages.error(self.request, message) return redirect('basket:summary') # Reload frozen basket which is specified in the URL kwargs['basket'] = self.load_frozen_basket(kwargs['basket_id']) if not kwargs['basket']: logger.warning('Unable to load frozen basket with ID %s', kwargs['basket_id']) message = _( 'No basket was found that corresponds to your PayPal transaction' ) messages.error(self.request, message) return redirect('basket:summary') if buyer_pays_on_paypal(): return self.submit(**self.build_submission( basket=kwargs['basket'])) logger.info( 'Basket #%s - showing preview with payer ID %s and token %s', kwargs['basket'].id, self.payer_id, self.token) return super().get(request, *args, **kwargs)
def get_paypal_url(basket, user=None, shipping_address=None, shipping_method=None, host=None): """ Return the URL for a PayPal Express transaction. This involves registering the txn with PayPal to get a one-time URL. If a shipping method and shipping address are passed, then these are given to PayPal directly - this is used within when using PayPal as a payment method. """ if basket.currency: currency = basket.currency else: currency = getattr(settings, 'PAYPAL_CURRENCY', 'GBP') if host is None: host = Site.objects.get_current().domain use_https = getattr(settings, 'PAYPAL_CALLBACK_HTTPS', True) scheme = 'https' if use_https else 'http' view_name = 'express-checkout-handle-order' if buyer_pays_on_paypal() else 'express-checkout-success-response' return_url_path = reverse(view_name, kwargs={'basket_id': basket.id}) return_url = f'{scheme}://{host}{return_url_path}' cancel_url_path = reverse('express-checkout-cancel-response', kwargs={'basket_id': basket.id}) cancel_url = f'{scheme}://{host}{cancel_url_path}' address = None if basket.is_shipping_required(): if shipping_address is not None: address = shipping_address elif user is not None: addresses = user.addresses.all().order_by('-is_default_for_billing') if addresses.exists(): address = addresses.first() shipping_charge = None order_total = basket.total_incl_tax if shipping_method: shipping_charge = shipping_method.calculate(basket).incl_tax order_total += shipping_charge intent = get_intent() result = PaymentProcessor().create_order( basket=basket, currency=currency, return_url=return_url, cancel_url=cancel_url, order_total=order_total, address=address, shipping_charge=shipping_charge, intent=intent, ) Transaction.objects.create( order_id=result.id, amount=order_total, currency=currency, status=result.status, intent=intent, ) for link in result.links: if link.rel == 'approve': return link.href