まずStripeでアカウントを作成し、商品を作る
本番環境で実際に使うには開業届などの信用のある証明書が必要になるが、テスト環境では誰でも利用できる。
ちなみにテスト環境でのバーチャルカード番号は42424242424242です。
stripeのインストール
pip install stripe
導入の流れは比較的簡単で、formをsubmitした後、バリデーションが通れば、Stripeの決済ページに飛ばす。その後、決済がうまくいったら、後ろにCHECKOUT_SESSION_IDをつけたURLを返してくれるのでそこでsuccessfulのページを表示する。
settings.pyにstripeからもらった秘密鍵を置く(詳しくは.envに)
#################################
#----------payments----------
#################################
STRIPE_SECRET_KEY = os.environ.get("stripe_secret_key")
PRICE_ID = os.environ.get("price_id")
urls.pyにはstripeの決済ページに飛ぶためのパスと成功後のパスを追加
from django.urls import path,include
from . import views
app_name = 'reservations'
urlpatterns = [
#予約ページ
path('', views.reservation, name="reservation"),
#決済完了後のページ
path('successful/', views.successful_view, name="successful"),
#stripeの決済ページ
path('create_checkout_session/', views.create_checkout_session, name='checkout_session'),
]
views.py
今回のシステムではメールアドレスをuniqueにしているので、customer_email=CUSTOMER_EMAILをつけることで、誰が支払ったか後でわかるようにしている。
from django.shortcuts import render
from django.views.generic.edit import CreateView
from django.shortcuts import redirect
from django.contrib import messages
from .models import Reservation
from .forms import ReservationForm
import stripe
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponseServerError
#stripeのsecretkeyを記述
stripe.api_key = settings.STRIPE_SECRET_KEY
PRICE_ID = settings.PRICE_ID
#-------------------------------------------------
# RESERVATION VIEWS
#-------------------------------------------------
class ReservationView(CreateView):
template_name = "reservations/reservation.html"
model = Reservation
form_class = ReservationForm
def get_initial(self):
initial = super().get_initial()
form_data = self.request.session.get('form_data')
if form_data:
initial.update(form_data)
elif self.request.user.is_authenticated:
initial['username'] = self.request.user.username
initial['email'] = self.request.user.email
initial['lang'] = self.request.user.lang
return initial
def post(self, request, *args, **kwargs):
form = ReservationForm(request.POST)
if request.POST.get("email") != request.POST.get("confirmed_mail"):
self.request.session['form_data'] = request.POST
messages.add_message(self.request, messages.WARNING, _("メールアドレスが一致しません"))
return redirect('reservations:reservation')
elif form.is_valid():
form = form.save(commit=False)
form.request_status = "not_yet"
form.payment_status = "not_yet"
if request.user.is_authenticated:
form.user_id = request.user.id
form.save()
self.request.session['form_data'] = None
#バリデーションに成功したらstripeの決済ページに飛ぶ
return create_checkout_session(request, form.id)
else:
messages.add_message(self.request, messages.WARNING, _("予約に失敗しました"))
return redirect('reservations:reservation')
reservation = ReservationView.as_view()
#-------------------------------------------------
# STRIPE VIEWS
#-------------------------------------------------
@csrf_exempt
def successful_view(request):
session_id = request.GET.get('session_id')
if session_id:
# 支払いが成功した場合の処理
reservation = Reservation.objects.get(payment_charge_id=session_id)
reservation.payment_status = "checked"
reservation.request_status = "ongoing"
reservation.payment_charge_id = session_id
reservation.save()
reservations = Reservation.objects.filter(payment_charge_id=session_id)
return render(request, 'reservations/successful.html', {'reservations': reservations})
else:
# 支払いが失敗した場合の処理
messages.error(request, _("カードの確認に失敗しました"))
return redirect('reservations:reservation')
#即時支払いの場合mode=payment
@csrf_exempt
def create_checkout_session(request, id):
MY_DOMAIN = f'{request.scheme}://{request.get_host()}'
PRICE_ID = "price_1PDzR1CEIHOn2yB6BFUR38pd"
reservation = Reservation.objects.get(id=id)
CUSTOMER_EMAIL=reservation.email
try:
checkout_session = stripe.checkout.Session.create(
line_items=[
{
'price': PRICE_ID,
'quantity': 1,
},
],
customer_email=CUSTOMER_EMAIL,
mode='payment',
success_url=MY_DOMAIN +
'/reservations/successful?session_id={CHECKOUT_SESSION_ID}',
cancel_url=MY_DOMAIN + '/reservations/reservation',
)
reservation.payment_charge_id = checkout_session.id
reservation.save()
return redirect(checkout_session.url)
except Exception as e:
print("エラー内容:"+str(e))
return HttpResponseServerError("支払いセッションの作成中にエラーが発生しました")
#後で請求する場合mode=setup
@csrf_exempt
def create_checkout_session(request, id):
MY_DOMAIN = f'{request.scheme}://{request.get_host()}'
reservation = Reservation.objects.get(id=id)
CUSTOMER_EMAIL=reservation.email
try:
checkout_session = stripe.checkout.Session.create(
customer_email=CUSTOMER_EMAIL,
customer_creation="always",
mode='setup',
currency='usd',
success_url=MY_DOMAIN +
'/reservations/successful?session_id={CHECKOUT_SESSION_ID}',
cancel_url=MY_DOMAIN + '/reservations/reservation',
)
reservation.payment_charge_id = checkout_session.id
reservation.save()
return redirect(checkout_session.url)
except Exception as e:
print("エラー内容:"+str(e))
return HttpResponseServerError(_("カード確認中にエラーが発生しました"))
webhookなどでユーザーと紐付けが行えるが、今回はその必要がないので割愛。
mode=”payment”にすると即時支払いがされるが、色々設定しないと追加での請求ができないのと、返金の際は決済手数料が返ってこないので、自分で請求する手間が負担にならないくらいのサービスなら、後で自分で請求できる”setup”が良いと思う。
この辺りはdocumentを読んで色々カスタマイズできる。