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.payer_id = request.POST['payer_id'] self.token = request.POST['token'] except KeyError: # Probably suspicious manipulation if we get here messages.error(self.request, self.error_message) return redirect('basket:summary') try: self.txn = fetch_transaction_details(self.token) except PayPalError: # Unable to fetch txn details from PayPal - we have to bail out messages.error(self.request, self.error_message) 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_message) 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 PayPalError as e: logger.warning( "Unable to fetch transaction details for token %s: %s", self.token, e) messages.error(self.request, self.error_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']) messages.error( self.request, _("No basket was found that corresponds to your PayPal transaction" )) 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(SuccessResponseView, self).get(request, *args, **kwargs)
def get_paypal_url(basket, shipping_methods, user=None, shipping_address=None, shipping_method=None, host=None, scheme=None, paypal_params=None, ccard=False): """ 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 if scheme is None: use_https = getattr(settings, 'PAYPAL_CALLBACK_HTTPS', True) scheme = 'https' if use_https else 'http' response_view_name = 'paypal-handle-order' if buyer_pays_on_paypal( ) else 'paypal-success-response' return_url = '%s://%s%s' % (scheme, host, reverse(response_view_name, kwargs={'basket_id': basket.id})) cancel_url = '%s://%s%s' % (scheme, host, reverse('paypal-cancel-response', kwargs={'basket_id': basket.id})) # URL for updating shipping methods - we only use this if we have a set of # shipping methods to choose between. update_url = None if shipping_methods: update_url = '%s://%s%s' % (scheme, host, reverse('paypal-shipping-options', kwargs={'basket_id': basket.id})) # Determine whether a shipping address is required no_shipping = False if not basket.is_shipping_required(): no_shipping = True # Pass a default billing address is there is one. This means PayPal can # pre-fill the registration form. address = None if user: addresses = user.addresses.all().order_by('-is_default_for_billing') if len(addresses): address = addresses[0] return set_txn(basket=basket, shipping_methods=shipping_methods, currency=currency, return_url=return_url, cancel_url=cancel_url, update_url=update_url, action=_get_payment_action(), shipping_method=shipping_method, shipping_address=shipping_address, user=user, user_address=address, no_shipping=no_shipping, paypal_params=paypal_params, ccard=ccard)
name='paypal-cancel-response'), # Callback for getting shipping options for a specific basket url(r'^shipping-options/(?P<basket_id>\d+)/(?P<country_code>\w+)?', csrf_exempt(views.ShippingOptionsView.as_view()), name='paypal-shipping-options'), # View for using PayPal as a payment method url(r'^payment/', views.RedirectView.as_view(as_payment_method=True), name='paypal-direct-payment'), ] buyer_pays_on_paypal_patterns = [ url(r'^handle-order/(?P<basket_id>\d+)/$', views.SuccessResponseView.as_view(preview=True), name='paypal-handle-order'), ] buyer_pays_on_website_patterns = [ url(r'^place-order/(?P<basket_id>\d+)/$', views.SuccessResponseView.as_view(), name='paypal-place-order'), url(r'^preview/(?P<basket_id>\d+)/$', views.SuccessResponseView.as_view(preview=True), name='paypal-success-response'), ] if buyer_pays_on_paypal(): urlpatterns = base_patterns + buyer_pays_on_paypal_patterns else: urlpatterns = base_patterns + buyer_pays_on_website_patterns