I have an e-commerce application that I'm working on. The app is currently hosted on Heroku free account. At the moment I can select a product, add it on the cart and can get up to the stripe form and type in the card details, but when I click the 'Submit Payment' button nothing happens. I don't even get an error message. I'm using Stripe test keys and 4242 four times as my card number. Can anyone help me to find out what's going on pliz. I have been stuck on it for days.
Here is the relevant code below:
Settings.py code:
from .base import *
import dj_database_urlDEBUG = (os.environ.get('DEBUG_VALUE') == 'True')
ALLOWED_HOSTS = ['.herokuapp.com', '127.0.0.1']AUTH_PASSWORD_VALIDATORS = [{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}
]""" DATABASES = {'default': {'ENGINE': 'django.db.backends.postgresql_psycopg2','NAME': config('DB_NAME'),'USER': config('DB_USER'),'PASSWORD': config('DB_PASSWORD'),'HOST': config('DB_HOST'),'PORT': ''}
}"""DATABASES = {'default': {'ENGINE': 'django.db.backends.sqlite3','NAME': os.path.join(BASE_DIR, 'db.sqlite3'),}
}STRIPE_PUBLIC_KEY = os.environ.get('STRIPE_LIVE_PUBLIC_KEY')
STRIPE_SECRET_KEY = os.environ.get('STRIPE_LIVE_SECRET_KEY')AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = NoneAWS_S3_REGION_NAME = "us-east-2"
AWS_S3_SIGNATURE_VERSION = "s3v4"DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('EMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASSWORD')# Heroku: Update database configuration from $DATABASE_URL.
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/# The absolute path to the directory where collectstatic will collect static files for deployment.
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static_in_env')]# The URL to use when referring to static files (where they will be served from)
STATIC_URL = '/static/'# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
views.py (Specifically the class PaymentView(View)):
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, View
from django.shortcuts import redirect
from django.utils import timezone
from django.db.models import Q
from .forms import CheckoutForm, CouponForm, RefundForm, PaymentForm
from .models import Item, OrderItem, Order, Address, Payment, Coupon, Refund, UserProfileimport random
import string
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEYclass PaymentView(View):def get(self, *args, **kwargs):order = Order.objects.get(user=self.request.user, ordered=False)if order.billing_address:context = {'order': order,'DISPLAY_COUPON_FORM': False}userprofile = self.request.user.userprofileif userprofile.one_click_purchasing:# fetch the users card listcards = stripe.Customer.list_sources(userprofile.stripe_customer_id,limit=3,object='card')card_list = cards['data']if len(card_list) > 0:# update the context with the default cardcontext.update({'card': card_list[0]})return render(self.request, "payment.html", context)else:messages.warning(self.request, "You have not added a billing address")return redirect("core:checkout")def post(self, *args, **kwargs):order = Order.objects.get(user=self.request.user, ordered=False)form = PaymentForm(self.request.POST)print('form')userprofile = UserProfile.objects.get(user=self.request.user)if form.is_valid():token = form.cleaned_data.get('stripeToken')# print('token')save = form.cleaned_data.get('save')use_default = form.cleaned_data.get('use_default')if save:if userprofile.stripe_customer_id != '' and userprofile.stripe_customer_id is not None:customer = stripe.Customer.retrieve(userprofile.stripe_customer_id)customer.sources.create(source=token)else:customer = stripe.Customer.create(email=self.request.user.email,)customer.sources.create(source=token)userprofile.stripe_customer_id = customer['id']userprofile.one_click_purchasing = Trueuserprofile.save()amount = order.get_total() * 100try:if use_default or save:# charge the customer because we cannot charge the token more than oncecharge = stripe.Charge.create(amount=amount, # centscurrency="usd",customer=userprofile.stripe_customer_id)else:# charge once off on the tokencharge = stripe.Charge.create(amount=amount, # centscurrency="usd",source=token)# create the paymentpayment = Payment()payment.stripe_charge_id = charge['id']payment.user = self.request.userpayment.amount = order.get_total()payment.save()# assign the payment to the orderorder_items = order.items.all()order_items.update(ordered=True)for item in order_items:item.save()order.ordered = Trueorder.payment = paymentorder.ref_code = create_ref_code()order.save()messages.success(self.request, "Your order was successful!")return redirect("/")except stripe.error.CardError as e:body = e.json_bodyerr = body.get('error', {})messages.warning(self.request, f"{err.get('message')}")return redirect("/")except stripe.error.RateLimitError as e:# Too many requests made to the API too quicklyprint(e)messages.warning(self.request, "Rate limit error")return redirect("/")except stripe.error.InvalidRequestError as e:# Invalid parameters were supplied to Stripe's APIprint(e)messages.warning(self.request, "Invalid parameters")return redirect("/")except stripe.error.AuthenticationError as e:# Authentication with Stripe's API failed# (maybe you changed API keys recently)print(e)messages.warning(self.request, "Not authenticated")return redirect("/")except stripe.error.APIConnectionError as e:# Network communication with Stripe failedprint(e)messages.warning(self.request, "Network error")return redirect("/")except stripe.error.StripeError as e:# Display a very generic error to the user, and maybe send# yourself an emailprint(e)messages.warning(self.request, "Something went wrong. You were not charged. Please try again.")return redirect("/")except Exception as e:# send an email to ourselvesprint(e)messages.warning(self.request, "A serious error occurred. We have been notifed.")return redirect("/")messages.warning(self.request, "Invalid data received")return redirect("/payment/stripe/")
payment.html:
{% extends "base.html" %}{% block extra_head %}
<style>#stripeBtnLabel {font-family: "Helvetica Neue", Helvetica, sans-serif;font-size: 16px;font-variant: normal;padding: 0;margin: 0;-webkit-font-smoothing: antialiased;font-weight: 500;display: block;}#stripeBtn {border: none;border-radius: 4px;outline: none;text-decoration: none;color: #fff;background: #32325d;white-space: nowrap;display: inline-block;height: 40px;line-height: 40px;box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);border-radius: 4px;font-size: 15px;font-weight: 600;letter-spacing: 0.025em;text-decoration: none;-webkit-transition: all 150ms ease;transition: all 150ms ease;float: left;width: 100%}button:hover {transform: translateY(-1px);box-shadow: 0 7px 14px rgba(50, 50, 93, .10), 0 3px 6px rgba(0, 0, 0, .08);background-color: #43458b;}.stripe-form {padding: 5px 30px;}#card-errors {height: 20px;padding: 4px 0;color: #fa755a;}.stripe-form-row {width: 100%;float: left;margin-top: 5px;margin-bottom: 5px;}/*** The CSS shown here will not be introduced in the Quickstart guide, but shows* how you can use CSS to style your Element's container.*/.StripeElement {box-sizing: border-box;height: 40px;padding: 10px 12px;border: 1px solid transparent;border-radius: 4px;background-color: white;box-shadow: 0 1px 3px 0 #e6ebf1;-webkit-transition: box-shadow 150ms ease;transition: box-shadow 150ms ease;}.StripeElement--focus {box-shadow: 0 1px 3px 0 #cfd7df;}.StripeElement--invalid {border-color: #fa755a;}.StripeElement--webkit-autofill {background-color: #fefde5 !important;}.current-card-form {display: none;}
</style>
{% endblock extra_head %}{% block content %}<main><div class="container wow fadeIn"><h2 class="my-5 h2 text-center">Payment</h2><div class="row"><div class="col-md-12 mb-4"><div class="card"><script src="https://js.stripe.com/v3/"></script>{% if card %}<div style="padding: 5px 30px;"><div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" name="use_default_card" id="use_default_card"><label class="custom-control-label" for="use_default_card">Use default card:**** **** **** {{ card.last4 }}<span>Exp: {{ card.exp_month }}/{{ card.exp_year }}</span></label></div></div>{% endif %}<div class="current-card-form"><form action="." method="post" class="stripe-form">{% csrf_token %}<input type="hidden" name="use_default" value="true"><div class="stripe-form-row"><button id="stripeBtn">Submit Payment</button></div><div id="card-errors" role="alert"></div></form></div><div class="new-card-form"><form action="." method="post" class="stripe-form" id="stripe-form">{% csrf_token %}<div class="stripe-form-row" id="creditCard"><label for="card-element" id="stripeBtnLabel">Credit or debit card</label><div id="card-element" class="StripeElement StripeElement--empty"><div class="__PrivateStripeElement"style="margin: 0px !important; padding: 0px !important; border: none !important; display: block !important; background: transparent !important; position: relative !important; opacity: 1 !important;"><iframe frameborder="0" allowtransparency="true" scrolling="no" name="__privateStripeFrame5"allowpaymentrequest="true"src="https://js.stripe.com/v3/elements-inner-card-19066928f2ed1ba3ffada645e45f5b50.html#style[base][color]=%2332325d&style[base][fontFamily]=%22Helvetica+Neue%22%2C+Helvetica%2C+sans-serif&style[base][fontSmoothing]=antialiased&style[base][fontSize]=16px&style[base][::placeholder][color]=%23aab7c4&style[invalid][color]=%23fa755a&style[invalid][iconColor]=%23fa755a&componentName=card&wait=false&rtl=false&keyMode=test&origin=https%3A%2F%2Fstripe.com&referrer=https%3A%2F%2Fstripe.com%2Fdocs%2Fstripe-js&controllerId=__privateStripeController1"title="Secure payment input frame"style="border: none !important; margin: 0px !important; padding: 0px !important; width: 1px !important; min-width: 100% !important; overflow: hidden !important; display: block !important; height: 19.2px;"></iframe><inputclass="__PrivateStripeElement-input" aria-hidden="true" aria-label=" " autocomplete="false"maxlength="1"style="border: none !important; display: block !important; position: absolute !important; height: 1px !important; top: 0px !important; left: 0px !important; padding: 0px !important; margin: 0px !important; width: 100% !important; opacity: 0 !important; background: transparent !important; pointer-events: none !important; font-size: 16px !important;"></div></div></div><div class="stripe-form-row"><button id="stripeBtn">Submit Payment</button></div><div class="stripe-form-row"><div class="custom-control custom-checkbox"><input type="checkbox" class="custom-control-input" name="save" id="save_card_info"><label class="custom-control-label" for="save_card_info">Save for future purchases{{ STRIPE_PUBLIC_KEY }} {{ STRIPE_SECRET_KEY }}</label></div></div><div id="card-errors" role="alert"></div></form></div></div></div>{% include "order_snippet.html" %}</div></div>
</main>{% endblock content %}{% block extra_scripts %}<script nonce=""> // Create a Stripe client.var stripe = Stripe('STRIPE_PUBLIC_KEY');// Create an instance of Elements.var elements = stripe.elements();// Custom styling can be passed to options when creating an Element.// (Note that this demo uses a wider set of styles than the guide below.)var style = {base: {color: '#32325d',fontFamily: '"Helvetica Neue", Helvetica, sans-serif',fontSmoothing: 'antialiased',fontSize: '16px','::placeholder': {color: '#aab7c4'}},invalid: {color: '#fa755a',iconColor: '#fa755a'}};// Create an instance of the card Element.var card = elements.create('card', { style: style });// Add an instance of the card Element into the `card-element` <div>.card.mount('#card-element');// Handle real-time validation errors from the card Element.card.addEventListener('change', function (event) {var displayError = document.getElementById('card-errors');if (event.error) {displayError.textContent = event.error.message;} else {displayError.textContent = '';}});// Handle form submission.var form = document.getElementById('stripe-form');form.addEventListener('submit', function (event) {event.preventDefault();stripe.createToken(card).then(function (result) {if (result.error) {// Inform the user if there was an error.var errorElement = document.getElementById('card-errors');errorElement.textContent = result.error.message;} else {// Send the token to your server.stripeTokenHandler(result.token);}});});// Submit the form with the token ID.function stripeTokenHandler(token) {// Insert the token ID into the form so it gets submitted to the servervar form = document.getElementById('stripe-form');var hiddenInput = document.createElement('input');hiddenInput.setAttribute('type', 'hidden');hiddenInput.setAttribute('name', 'stripeToken');hiddenInput.setAttribute('value', token.id);form.appendChild(hiddenInput);// Submit the formform.submit();}var currentCardForm = $('.current-card-form');var newCardForm = $('.new-card-form');var use_default_card = document.querySelector("input[name=use_default_card]");use_default_card.addEventListener('change', function () {if (this.checked) {newCardForm.hide();currentCardForm.show()} else {newCardForm.show();currentCardForm.hide()}})</script>{% endblock extra_scripts %}