学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Django3.2 | クラウドソーシングアプリの構築 | 23 | クレジットカード登録

↓↓クリックして頂けると励みになります。


22 | Stripe】 << 【ホーム】 >> 【24 | 配達依頼


「core/templates/customer/payment_method.html」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/templates/customer/payment_method.html】

{% extends 'customer/base.html' %}
{% load bootstrap4 %}

{% block head %}
<script src="https://js.stripe.com/v3/"></script>

<style>
    .StripeElement {
      height: 40px;
      padding: 10px 12px;
      width: 100%;
      color: #32325d;
      background-color: white;
      /* border: 1px solid transparent; */
      border: 1px solid #ced4da;
      border-radius: 4px;
  
      /* box-shadow: 0 1px 3px 0 #e6ebf1;
      -webkit-transition: box-shadow 150ms ease;
      transition: box-shadow 150ms ease; */
    }
  
    .StripeElement--focus {
      border-color: #80bdff;
      box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, .25);
    }
  
    .StripeElement--invalid {
      border-color: #fa755a;
    }
  
    .StripeElement--webkit-autofill {
      background-color: #fefde5 !important;
    }
  </style>
{% endblock %}

{% block main %}

<b class="text-secondary">クレジットカード登録</b>

<div class="card bg-white mt-2 mb-5">
  <div class="card-body">

    {% if request.user.customer.stripe_payment_method_id %}
    <div id="change-card" class="input-group">
      <input type="text" class="form-control" disabled
        value="**** **** **** {{ request.user.customer.stripe_card_last4 }}">
      <div class="input-group-append">
        <form method="POST">
          {% csrf_token %}
          <button type="submit" class="btn btn-danger">カード登録削除</button>
        </form>
      </div>
    </div>

    {% else %}
    <form id="setup-form" data-secret="{{ client_secret }}">
      <div id="card-element"></div>
      <button id="card-button" class="btn btn-danger mt-3" type="button">
        カード登録
      </button>
    </form>
    {% endif %}


  </div>
</div>

<script>

    var stripe = Stripe("{{ STRIPE_API_PUBLIC_KEY }}");

    var elements = stripe.elements();
    var cardElement = elements.create('card');
    cardElement.mount('#card-element');

    var cardholderName = document.getElementById('cardholder-name');
    var cardButton = document.getElementById('card-button');
    var clientSecret = "{{ client_secret }}";

    cardButton.addEventListener('click', function (ev) {

        stripe.confirmCardSetup(
        clientSecret,
        {
            payment_method: {
            card: cardElement,
            },
        }
        ).then(function (result) {
        if (result.error) {
            // Display error.message in your UI.
            toast(result.error.message, 'error');
        } else {
            toast("クレジットカードが登録されました。", 'success');
            window.location.reload();
            // The setup has succeeded. Display a success message.
        }
        });
    });    

</script>

{% endblock %}



「core/customer/views.py」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/customer/views.py】

import firebase_admin
from firebase_admin import credentials, auth
import stripe

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from core.customer import forms

from django.contrib import messages
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth import update_session_auth_hash
from django.conf import settings

cred = credentials.Certificate(settings.FIREBASE_ADMIN_CREDENTIAL)
firebase_admin.initialize_app(cred)

stripe.api_key = settings.STRIPE_API_SECRET_KEY

@login_required()
def home(request):
    return redirect(reverse('customer:profile'))

@login_required(login_url="/sign-in/?next=/customer/")
def profile_page(request):
    user_form = forms.BasicUserForm(instance=request.user)
    customer_form = forms.BasicCustomerForm(instance=request.user.customer)
    password_form = PasswordChangeForm(request.user)

    if request.method == "POST":
 
        if request.POST.get('action') == 'update_profile':
            user_form = forms.BasicUserForm(request.POST, instance=request.user)
            customer_form = forms.BasicCustomerForm(request.POST, request.FILES, instance=request.user.customer)

            if user_form.is_valid() and customer_form.is_valid():
                user_form.save()
                customer_form.save()

                messages.success(request, 'プロフィールが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_password':
            password_form = PasswordChangeForm(request.user, request.POST)
            if password_form.is_valid():
                user = password_form.save()
                update_session_auth_hash(request, user)

                messages.success(request, 'パスワードが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_phone':
            # Get Firebase user data
            firebase_user = auth.verify_id_token(request.POST.get('id_token'))

            request.user.customer.phone_number = firebase_user['phone_number']
            request.user.customer.save()
            messages.success(request, '電話番号が更新されました。')
            return redirect(reverse('customer:profile'))

    return render(request, 'customer/profile.html', {
        "user_form": user_form,
        "customer_form": customer_form,
        "password_form": password_form,
    })

@login_required(login_url="/sign-in/?next=/customer/")
def payment_method_page(request):
    current_customer = request.user.customer

    # Save stripe customer infor
    if not current_customer.stripe_customer_id:
        customer = stripe.Customer.create()
        current_customer.stripe_customer_id = customer['id']
        current_customer.save()    

    # Get Stripe payment method
    stripe_payment_methods = stripe.PaymentMethod.list(
        customer = current_customer.stripe_customer_id,
        type = "card",
    )

    print(stripe_payment_methods)

    if stripe_payment_methods and len(stripe_payment_methods.data) > 0:
        payment_method = stripe_payment_methods.data[0]
        current_customer.stripe_payment_method_id = payment_method.id
        current_customer.stripe_card_last4 = payment_method.card.last4
        current_customer.save()
    else:
        current_customer.stripe_payment_method_id = ""
        current_customer.stripe_card_last4 = ""
        current_customer.save()


    intent = stripe.SetupIntent.create(
        customer = current_customer.stripe_customer_id
    )

    return render(request, 'customer/payment_method.html', {
        "client_secret": intent.client_secret,
        "STRIPE_API_PUBLIC_KEY": settings.STRIPE_API_PUBLIC_KEY,
    })



これでクレジットカード登録ができるようになりました。
テストカード「4242 4242 4242 4242」を登録して試します。
http://127.0.0.1:8000/customer/payment_method/
StripeIDとカードの下4桁が登録されているのがわかります。

データベースに登録
データベースに登録



Stripeにも顧客情報が登録されました。

Stripe登録
Stripe登録



カード削除ボタンを実装していきます。


「core/templates/customer/payment_method.html」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/templates/customer/payment_method.html】

{% extends 'customer/base.html' %}
{% load bootstrap4 %}

{% block head %}
<script src="https://js.stripe.com/v3/"></script>

<style>
    .StripeElement {
      height: 40px;
      padding: 10px 12px;
      width: 100%;
      color: #32325d;
      background-color: white;
      /* border: 1px solid transparent; */
      border: 1px solid #ced4da;
      border-radius: 4px;
  
      /* box-shadow: 0 1px 3px 0 #e6ebf1;
      -webkit-transition: box-shadow 150ms ease;
      transition: box-shadow 150ms ease; */
    }
  
    .StripeElement--focus {
      border-color: #80bdff;
      box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, .25);
    }
  
    .StripeElement--invalid {
      border-color: #fa755a;
    }
  
    .StripeElement--webkit-autofill {
      background-color: #fefde5 !important;
    }
  </style>
{% endblock %}

{% block main %}

{% if not request.user.customer.stripe_payment_method_id %}
<div class="alert alert-danger alert-dismissible fade show" role="alert">
  仕事を登録するにはクレジットカードを追加する必要があります。
  <button type="button" class="close" data-dismiss="alert" aria-label="Close">
    <span aria-hidden="true">&times;</span>
  </button>
</div>
{% endif %}

<b class="text-secondary">クレジットカード登録</b>

<div class="card bg-white mt-2 mb-5">
  <div class="card-body">

    {% if request.user.customer.stripe_payment_method_id %}
    <div id="change-card" class="input-group">
      <input type="text" class="form-control" disabled
        value="**** **** **** {{ request.user.customer.stripe_card_last4 }}">
      <div class="input-group-append">
        <form method="POST">
          {% csrf_token %}
          <button type="submit" class="btn btn-danger">削除</button>
        </form>
      </div>
    </div>

    {% else %}
    <form id="setup-form" data-secret="{{ client_secret }}">
      <div id="card-element"></div>
      <button id="card-button" class="btn btn-info mt-3" type="button">
        クレジットカード登録
      </button>
    </form>
    {% endif %}

  </div>
</div>

{% if not request.user.customer.stripe_payment_method_id %}
<script>
  var stripe = Stripe("{{ STRIPE_API_PUBLIC_KEY }}");

  var elements = stripe.elements();
  var cardElement = elements.create('card');
  cardElement.mount('#card-element');

  var cardholderName = document.getElementById('cardholder-name');
  var cardButton = document.getElementById('card-button');
  var clientSecret = "{{ client_secret }}";

  cardButton.addEventListener('click', function (ev) {

    stripe.confirmCardSetup(
      clientSecret,
      {
        payment_method: {
          card: cardElement,
        },
      }
    ).then(function (result) {
      if (result.error) {
        // Display error.message in your UI.
        toast(result.error.message, 'error');
      } else {
        toast("クレジットカードが登録されました。", 'success');
        window.location.reload();
        // The setup has succeeded. Display a success message.
      }
    });
  });
</script>
{% endif %}

{% endblock %}



「core/customer/views.py」ファイルを編集します。


記述編集 【Desktop/crowdsource/core/customer/views.py】

import firebase_admin
from firebase_admin import credentials, auth
import stripe

from django.shortcuts import render, redirect
from django.contrib.auth.decorators import login_required
from django.urls import reverse
from core.customer import forms

from django.contrib import messages
from django.contrib.auth.forms import PasswordChangeForm
from django.contrib.auth import update_session_auth_hash
from django.conf import settings

cred = credentials.Certificate(settings.FIREBASE_ADMIN_CREDENTIAL)
firebase_admin.initialize_app(cred)

stripe.api_key = settings.STRIPE_API_SECRET_KEY

@login_required()
def home(request):
    return redirect(reverse('customer:profile'))

@login_required(login_url="/sign-in/?next=/customer/")
def profile_page(request):
    user_form = forms.BasicUserForm(instance=request.user)
    customer_form = forms.BasicCustomerForm(instance=request.user.customer)
    password_form = PasswordChangeForm(request.user)

    if request.method == "POST":
 
        if request.POST.get('action') == 'update_profile':
            user_form = forms.BasicUserForm(request.POST, instance=request.user)
            customer_form = forms.BasicCustomerForm(request.POST, request.FILES, instance=request.user.customer)

            if user_form.is_valid() and customer_form.is_valid():
                user_form.save()
                customer_form.save()

                messages.success(request, 'プロフィールが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_password':
            password_form = PasswordChangeForm(request.user, request.POST)
            if password_form.is_valid():
                user = password_form.save()
                update_session_auth_hash(request, user)

                messages.success(request, 'パスワードが更新されました。')
                return redirect(reverse('customer:profile'))

        elif request.POST.get('action') == 'update_phone':
            # Get Firebase user data
            firebase_user = auth.verify_id_token(request.POST.get('id_token'))

            request.user.customer.phone_number = firebase_user['phone_number']
            request.user.customer.save()
            messages.success(request, '電話番号が更新されました。')
            return redirect(reverse('customer:profile'))

    return render(request, 'customer/profile.html', {
        "user_form": user_form,
        "customer_form": customer_form,
        "password_form": password_form,
    })

@login_required(login_url="/sign-in/?next=/customer/")
def payment_method_page(request):
    current_customer = request.user.customer

    # Remove existing card
    if request.method == "POST":
        stripe.PaymentMethod.detach(current_customer.stripe_payment_method_id)
        current_customer.stripe_payment_method_id = ""
        current_customer.stripe_card_last4 = ""
        current_customer.save()
        return redirect(reverse('customer:payment_method'))

    # Save stripe customer infor
    if not current_customer.stripe_customer_id:
        customer = stripe.Customer.create()
        current_customer.stripe_customer_id = customer['id']
        current_customer.save()    

    # Get Stripe payment method
    stripe_payment_methods = stripe.PaymentMethod.list(
        customer = current_customer.stripe_customer_id,
        type = "card",
    )

    print(stripe_payment_methods)

    if stripe_payment_methods and len(stripe_payment_methods.data) > 0:
        payment_method = stripe_payment_methods.data[0]
        current_customer.stripe_payment_method_id = payment_method.id
        current_customer.stripe_card_last4 = payment_method.card.last4
        current_customer.save()
    else:
        current_customer.stripe_payment_method_id = ""
        current_customer.stripe_card_last4 = ""
        current_customer.save()


    if not current_customer.stripe_payment_method_id:
        intent = stripe.SetupIntent.create(
            customer = current_customer.stripe_customer_id
        )

        return render(request, 'customer/payment_method.html', {
            "client_secret": intent.client_secret,
            "STRIPE_API_PUBLIC_KEY": settings.STRIPE_API_PUBLIC_KEY,
        })
    else:
        return render(request, 'customer/payment_method.html')



ブラウザを確認します。
http://127.0.0.1:8000/customer/payment_method/
削除機能が実装されました。

削除機能実装
削除機能実装


↓↓クリックして頂けると励みになります。


22 | Stripe】 << 【ホーム】 >> 【24 | 配達依頼