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

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

Rails7.1 | 仕事売買アプリ作成 | 42 | Stripe Connect

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



41 | Stripe】 << 【ホーム】 >> 【43 | クレジットカード決済


Stripe Connect
Stripe Connect

Stripe Connectは、Stripeが提供するプラットフォーム型支払いソリューションです。
Stripeは、オンラインプラットフォームやマーケットプレイスが支払いの受け渡し、処理、および管理を行うための機能を提供することを可能にするためにStripe Connectを導入しました。

Stripe Connectは、さまざまな業界で使用されており、エンタープライズからスタートアップまで幅広い規模のビジネスに適しています。
オンラインマーケットプレイス、サブスクリプションベースのプラットフォーム、クラウドファンディングサイトなど、多くのプラットフォームがStripe Connectを活用しています。

仕事を登録したフリーランサーに報酬の80%が自動で支払われるように設定します。

Stripeコネクトのプランには「スタンダード」と「エクスプレス」があります。
「エクスプレス」の方がフリーランサーの登録や設定が楽なので「エクスプレス」で実装していきます。



「テスト環境のクライアント ID」の取得方法は下記の手順でお願いします。
mrradiology.hatenablog.jp


記述追加 GemFile(88行目)

gem 'omniauth-stripe-connect-v2', '~> 1.0', '>= 1.0.4'



コマンド
bundle


ユーザテーブルにStripeコネクトのIDを入れるカラムを作成します。


コマンド
rails g migration AddMerchantIdToUser merchant_id


マイグレーションを適用します。
コマンド マイグレーション適用
rails db:migrate


「app\models\user.rb」ファイルを編集します。


記述追加 app\models\user.rb(38行目)

  def is_active_host
    !self.merchant_id.blank?
  end



app\models\user.rb

class User < ApplicationRecord

  has_many :gigs
  has_many :requests
  has_many :offers
  has_many :buying_orders, foreign_key: "buyer_id", class_name: "Order"
  has_many :selling_orders, foreign_key: "seller_id", class_name: "Order"

  has_one_attached :avatar

  validates :full_name, presence: true, length: {maximum: 50}
  
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
          :confirmable, :omniauthable

  def self.from_omniauth(auth)
    user = User.where(email: auth.info.email).first

    if user
      return user
    else
      where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
        user.email = auth.info.email
        user.password = Devise.friendly_token[0, 20]
        user.full_name = auth.info.name   # ユーザーモデルに名前があると仮定
        user.image = auth.info.image # ユーザーモデルに画像があると仮定

        user.uid = auth.uid
        user.provider = auth.provider

      end
    end
  end

  def is_active_host
    !self.merchant_id.blank?
  end
  
end



テスト環境のクライアントIDを確認します。
Stripeダッシュボードで右上の歯車マークをクリックし、Connectの設定をクリックします。

コネクトの設定
コネクトの設定



「OAuth 設定」でExpressアカウントのOAuthを有効にしてください。

OAuthを有効にする
OAuthを有効にする



リダイレクトURLを追加します。
追加するURLを「http://localhost:3000/auth/stripe_connect/callback」とします。

リダイレクトURLを追加
リダイレクトURLを追加



テスト環境のクライアントIDをコピーします。

テスト環境のクライアントID
テスト環境のクライアントID



記述追加 config\initializers\devise.rb(329行目)
ご自分のテスト環境のConnectクライアント IDとシークレットキーを入れて下さい。
シークレットキーはStripe APIキーのシークレットキーです。

  # stripeコネクト
  # 最初にテスト環境のクライアント ID(コネクトのID) ca_
  # 次にシークレットキー sk_test_
  config.omniauth :stripe_connect, 'ご自分のクライアントIDを入れてください', 'ご自分のシークレットキーを入れてください', scope: 'read_write', stripe_landing: 'login'



記述追加 app\helpers\application_helper.rb(22行目)
「client_id=」と「&scope=read_write」の間にご自分のテスト環境のクライアント ID(コネクトのID)を入れて下さい。

    # テスト環境のクライアント ID(コネクトのID) ca_
    def stripe_express_path
        "https://connect.stripe.com/express/oauth/authorize?response_type=code&client_id=ご自分のクライアントIDを入れてください&scope=read_write"
    end



app\helpers\application_helper.rb

module ApplicationHelper

    def avatar_url(user)
        if user.avatar.attached?
            url_for(user.avatar)
        elsif user.image?
            user.image
        else
            ActionController::Base.helpers.asset_path('icon_default_avatar.jpg')
        end
    end    

    def room_cover(room)
        if room.photos.attached?
            url_for(room.photos[0])
        else
            ActionController::Base.helpers.asset_path('blank.jpg')
        end
    end

    # テスト環境のクライアント ID(コネクトのID) ca_HZ3ThjQzL***
    def stripe_express_path
        "https://connect.stripe.com/express/oauth/authorize?response_type=code&client_id=ca_HZ3ThjQzL***&scope=read_write"
    end

end



ユーザーコントローラーにメソッドを追加します。
記述追加 app\controllers\users_controller.rb(47行目)

  def payout
    if !current_user.merchant_id.blank?
      account = Stripe::Account.retrieve(current_user.merchant_id)
      @login_link = account.login_links.create()
    end
  end



app\controllers\users_controller.rb

class UsersController < ApplicationController
  
  before_action :authenticate_user!

  def dashboard
    @reviews = Review.where(buyer_id: current_user.id).all.order("created_at desc")
  end

  def show
    @user = User.find(params[:id])
    @reviews = Review.where(seller_id: params[:id]).order("created_at desc")
  end

  def update
    @user = current_user
    if @user.update(current_user_params)
      flash[:notice] = "保存しました"
    else
      flash[:alert] = "更新できません"
    end
    redirect_to dashboard_path
  end

  def update_payment
    if !current_user.stripe_id
      customer = Stripe::Customer.create(
        email: current_user.email,
        source: params[:stripeToken]
      )
    else
      customer = Stripe::Customer.update(
        current_user.stripe_id,
        source: params[:stripeToken]
      )
    end
    if current_user.update(stripe_id: customer.id, stripe_last_4: customer.sources.data.first["last4"])
      flash[:notice] = "新しいカード情報が登録されました"
    else
      flash[:alert] = "無効なカードです"
    end
    redirect_to request.referrer
  rescue Stripe::CardError => e
    flash[:alert] = e.message
    redirect_to request.referrer
  end

  def payout
    if !current_user.merchant_id.blank?
      account = Stripe::Account.retrieve(current_user.merchant_id)
      @login_link = account.login_links.create()
    end
  end

  private
  def current_user_params
    params.require(:user).permit(:about, :status, :avatar)
  end

end



「app/controllers/omniauth_callbacks_controller.rb」ファイルに以下の記述を追加します。(28行目)

    def stripe_connect
      auth_data = request.env["omniauth.auth"]
      @user = current_user

      if @user.persisted?
        @user.merchant_id = auth_data.uid
        @user.save

        if !@user.merchant_id.blank?

            # 支払いスケジュールを更新する
            account = Stripe::Account.retrieve(current_user.merchant_id)
            # 決算の15日後にお支払い  
            account.settings.payouts.schedule.delay_days = 15

            account.save

            logger.debug "#{account}"
        end

        sign_in_and_redirect @user, event: :authentication
        flash[:notice] = "ストライプアカウントを作成し接続しました。" if is_navigational_format?

      else
        session["devise.stripe_connect_data"] = request.env["omniauth.auth"]
        redirect_to dashboard_path
      end
    end



app\controllers\omniauth_callbacks_controller.rb

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
    def facebook
 
      @user = User.from_omniauth(request.env["omniauth.auth"])
  
      if @user.persisted?
        sign_in_and_redirect @user, event: :authentication # @userがアクティブ化されていない場合
        set_flash_message(:notice, :success, kind: "Facebook") if is_navigational_format?
      else
        session["devise.facebook_data"] = request.env["omniauth.auth"]
        redirect_to new_user_registration_url
      end
    end

    def google_oauth2
        # 以下のメソッドをモデルに実装する必要があります(app/models/user.rb)
        @user = User.from_omniauth(request.env['omniauth.auth'])
    
        if @user.persisted?
          flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Google'
          sign_in_and_redirect @user, event: :authentication
        else
          session['devise.google_data'] = request.env['omniauth.auth'].except(:extra)
          redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
        end
    end    

    def stripe_connect
      auth_data = request.env["omniauth.auth"]
      @user = current_user

      if @user.persisted?
        @user.merchant_id = auth_data.uid
        @user.save

        if !@user.merchant_id.blank?

            # 支払いスケジュールを更新する
            account = Stripe::Account.retrieve(current_user.merchant_id)
            # 決算の15日後にお支払い  
            account.settings.payouts.schedule.delay_days = 15

            account.save

            logger.debug "#{account}"
        end

        sign_in_and_redirect @user, event: :authentication
        flash[:notice] = "ストライプアカウントを作成し接続しました。" if is_navigational_format?

      else
        session["devise.stripe_connect_data"] = request.env["omniauth.auth"]
        redirect_to dashboard_path
      end
    end

    def failure
      redirect_to root_path
    end
end



「app/assets/config/manifest.js」ファイルに記述を追加します。


記述追加 app/assets/config/manifest.js(6行目)

//= link stripe_button.png



app/assets/config/manifest.js

//= link_tree ../images
//= link_directory ../stylesheets .css
//= link_tree ../../javascript .js
//= link_tree ../../../vendor/javascript .js
//= link trestle/auth/userbox.css
//= link stripe_button.png





ルートの設定をします。


17行目に以下の記述を追加します。

get 'settings/payout', to: 'users#payout', as: 'settings_payout'



config\routes.rb

Rails.application.routes.draw do

  # ルートを app\views\pages\home.html.erb に設定
  root 'pages#home'

  # get
  get 'pages/home'
  get '/dashboard', to: 'users#dashboard'
  get '/users/:id', to: 'users#show', as: 'user'
  get '/selling_orders', to: 'orders#selling_orders'
  get '/buying_orders', to: 'orders#buying_orders'
  get '/all_requests', to: 'requests#list'
  get '/request_offers/:id', to: 'requests#offers', as: 'request_offers'
  get '/my_offers', to: 'requests#my_offers'
  get '/search', to: 'pages#search'
  get 'settings/payment', to: 'users#payment', as: 'settings_payment'
  get 'settings/payout', to: 'users#payout', as: 'settings_payout'

  # post
  post '/users/edit', to: 'users#update'
  post '/offers', to: 'offers#create'
  post '/reviews', to: 'reviews#create'
  post '/search', to: 'pages#search'
  post '/settings/payment', to: 'users#update_payment', as: "update_payment"

  # put
  put '/orders/:id/complete', to: 'orders#complete', as: 'complete_order'
  put '/offers/:id/accept', to: 'offers#accept', as: 'accept_offer'
  put '/offers/:id/reject', to: 'offers#reject', as: 'reject_offer'

  resources :gigs do
    member do
      delete :delete_photo
      post :upload_photo
    end
    resources :orders, only: [:create]
  end

  resources :requests
  resources :reviews, only: [:create, :destroy]
  
  # device
  devise_for :users, 
    path: '', 
    path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'},
    controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'}
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
  # Can be used by load balancers and uptime monitors to verify that the app is live.
  get "up" => "rails/health#show", as: :rails_health_check

  # Defines the root path route ("/")
  # root "posts#index"
end



ビューを作成します。
「app\views\users」フォルダに「payout.html.erb」ファイルを新規作成してください。


また、なんでも良いので「stripe_button.png」ファイルを「app/assets/images」フォルダに入れておいてください。


app\views\users\payout.html.erb(新規作成したファイル)

<div class="container mt-4">
    <div class="card">
        <div class="card-body">

                <h4 class="font2 text-primary">
                    <% if current_user.merchant_id.blank? %>
                        <i class="far fa-credit-card"></i>振込口座の登録
                    <% else %>
                        <i class="far fa-credit-card"></i>振込金額の確認
                    <% end %>
                </h4>

                <% if current_user.merchant_id.blank? %>            
                    <p class="font2">
                        Stripeというサービスを利用して振込口座を登録します。<br/>
                        仕事をして得た報酬はここで登録した振込先に振り込まれます。<br/>
                        <br/>
        
                        下のボタンを押してアカウントに振込先を登録して下さい。
                    </p>
                    <div>
                        <%= link_to image_tag('stripe_button.png'), stripe_express_path %>
                    </div>

                <% else %>

                    <p class="font2">
                        仕事をして得た報酬の振込金額をここで確認することができます。<br/>
                        <br/>
        
                        下のボタンを押すと振り込み金額の確認ができます。
                    </p>

                    <div>
                        <%= link_to "振込金額の確認", @login_link.url, class: "btn btn-outline-danger rounded-pill", target: :_blank %>
                    </div>
                <% end %>
            </div>
        </div>
    </div>
</div>



ブラウザを確認します。
Webサーバーを一度再起動してください。
ブラウザ確認
http://localhost:3000/settings/payout


コネクトボタンを押すとホストの振込口座の登録ができます。

PCレイアウト
PCレイアウト


モバイルレイアウト
モバイルレイアウト



テストアカウントを使えば比較的スムーズにテストできますが、一部、入力を行わなければならない箇所があります。


テストで登録をしてみます。
ホストのアカウントで行ってください。
「テスト用電話番号」をクリックして続けます。

テスト用電話番号
テスト用電話番号



テスト用コードを使用して次へ進みます。

テスト用コード
テスト用コード



個人事業主を選択して続けます。

個人事業主
個人事業主



個人情報の確認も適当でいいので入力して続けます。

個人情報の確認
個人情報の確認



事業詳細も適当で大丈夫ですが、Webページのアドレスに何か入れなければなりません。
この記事のアドレスでも入れておいてください。

事業詳細
事業詳細



口座はテストのものを使ってください。

テスト口座使用
テスト口座使用



あとは同意して送信すれば、ストライプIDを取得できます。

同意して送信
同意して送信



「merchant_id」にストライプのIDが格納されています。

merchant_id
merchant_id



ストライプのダッシュボードページで連結されたアカウントの詳細が確認できます。

連結されたアカウント
連結されたアカウント


登録が終わると、振込金額の確認ボタンがでます。
このボタンをクリックすると、Stripe Expressの金額確認ページが開きます。

振込金額の確認
振込金額の確認


Stripe Express
Stripe Express



ナビゲーションバーのリンクを追加します。


記述追加 app\views\shared\_navbar.html.erb(40行目)

<li><%= link_to  "振込口座登録", settings_payout_path, class: "dropdown-item btn btn-light", data: { turbo: false} %></li>



app\views\shared\_navbar.html.erb

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="/" ><span class="font1">Gig Hub7</span></a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav me-auto mb-2 mb-lg-0">
        <!-- もしログインしていなかったら-->
        <% if (!user_signed_in?) %>
        <li class="nav-item" style="margin-bottom: 0.1rem;">
          <span style="margin-left: 1rem;">
          <%= link_to  "新規登録", new_user_registration_path, class: "btn btn-danger" %>
          </span>
        </li>
        <li class="nav-item">
          <span style="margin-left: 1rem;">
            <%= link_to  "ログイン", new_user_session_path, class: "btn btn-success text-light" %>
          </span>
        </li>
      </ul>
      <!-- ログインしていたら -->
      <% else %>
      <ul class="navbar-nav" style="margin-left: 2rem;">
        <li class="nav-item dropdown">
          <a class="nav-link dropdown-toggle" href="#" role="button" data-bs-toggle="dropdown" aria-expanded="false">

          <figure style="position:relative; top: 0.2rem;" class="avatar <%= current_user.status ? "online" : "offline" %>"></figure>  
          <%= image_tag avatar_url(current_user), class: "bd-placeholder-img figure-img img-fluid rounded-pill", style: "width: 40px; height: 30px;" %>          
            <%= current_user.full_name %>
          </a>
          <ul class="dropdown-menu">
          <li><%= link_to  "ダッシュボード", dashboard_path, class: "dropdown-item btn btn-lightt" %></li>
          <li><%= link_to  "ユーザ登録情報編集", edit_user_registration_path, class: "dropdown-item btn btn-light" %></li>
          <li><%= link_to  "リクエスト", all_requests_path, class: "dropdown-item btn btn-light" %></li>
          <li><hr class="dropdown-divider"><span class="badge bg-danger" style="margin-left: 1rem;">フリーランサー</span></li>
          <li><%= link_to  "仕事を新規登録", new_gig_path, class: "dropdown-item btn btn-light" %></li>
          <li><%= link_to  "仕事確認", selling_orders_path, class: "dropdown-item btn btn-light" %></li>
          <li><%= link_to  "申し込み確認", my_offers_path, class: "dropdown-item btn btn-light" %></li>
          <li><%= link_to  "振込口座登録", settings_payout_path, class: "dropdown-item btn btn-light", data: { turbo: false} %>
          <li><hr class="dropdown-divider"><span class="badge bg-primary" style="margin-left: 1rem;">クライアント</span></li>
          <li><%= link_to  "依頼確認", buying_orders_path, class: "dropdown-item btn btn-light" %></li>
          <li><%= link_to  "リクエスト登録", new_request_path, class: "dropdown-item btn btn-light" %></li>
          <li><%= link_to  "リクエスト確認", requests_path, class: "dropdown-item btn btn-light" %></li>
          <li><%= link_to  "クレジットカード登録", settings_payment_path, class: "dropdown-item btn btn-light", data: { turbo: false} %></li>
          <li><hr class="dropdown-divider"></li>
            <li><%= button_to  "ログアウト", destroy_user_session_path, method: :delete, class: "dropdown-item btn btn-light" %></li>
          </ul>
        </li>
      </ul>
      <% end %>

    </div>
  </div>
</nav>


振込口座登録
振込口座登録





41 | Stripe】 << 【ホーム】 >> 【43 | クレジットカード決済




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