web-dev-qa-db-ja.com

クレジットカード情報の変更(ストライプ)

このチュートリアルを使用して、Stripes Monthly Billingを実装する方法をついに理解しました。http://railscasts.com/episodes/288-billing- with-stripe

これまでのところ、ユーザーはStripeを使用してサブスクリプションを作成および削除できます。

しかし、サブスクリプションを作成した後、ユーザーはどのようにしてクレジットカード情報を変更できますか

これはコメントと質問のある私のコードです。 Railsの初心者を助けてください。 :)

[〜#〜]コントローラー[〜#〜]

class SubscriptionsController < ApplicationController

  def new
    plan = Plan.find(params[:plan_id])
    @subscription = plan.subscriptions.build
    @subscription.user_id = current_user.id
  end

  def create
    @subscription = Subscription.new(params[:subscription])
    if @subscription.save_with_payment
      redirect_to @subscription, :notice => "Thank you for subscribing!"
    else
      render :new
    end
  end

  def update
    @subscription = current_user.subscription
     if @subscription.save
      redirect_to edit_subscription_path, :success => 'Updated Card.' 
    else
      flash.alert = 'Unable to update card.'
      render :edit 
    end
  end

end

[〜#〜]モデル[〜#〜]

class Subscription < ActiveRecord::Base
  attr_accessible :plan_id, :user_id, :email, :stripe_customer_token, :last_4_digits,
              :card_token, :card_name, :exp_month, :exp_year, :stripe_card_token

  attr_accessor :stripe_card_token

  belongs_to :plan
  belongs_to :user

  def save_with_payment
    if valid?
      save_with_stripe_payment
    end
  end

  def save_with_stripe_payment
    customer = Stripe::Customer.create(card: stripe_card_token, email: email, plan: plan_id, description: "Unlimited Comics")
    self.stripe_customer_token = customer.id
    self.card_token = customer.cards.data.first["id"]
    self.card_name = customer.cards.data.first["type"]
    self.exp_month = customer.cards.data.first["exp_month"]
    self.exp_year = customer.cards.data.first["exp_year"]
    self.last_4_digits = customer.cards.data.first["last4"]
    save!
  rescue Stripe::InvalidRequestError => e
    logger.error "Stripe error while creating customer: #{e.message}"
    errors.add :base, "There was a problem with your credit card."
    false
  end

  def update_card
    customer = Stripe::Customer.retrieve(stripe_customer_token)
    card = customer.cards.retrieve(card_token)

    *** This Update works, but how do I pass a new Credit Card Number, Expiration Date etc.
    card.name = "My new name"
    customer.save 
  rescue Stripe::StripeError => e 
    logger.error "Stripe Error: " + e.message 
    errors.add :base, "#{e.message}." 
    false
  end

end

[〜#〜]ビュー[〜#〜]

<%= form_for @subscription do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

  <%= f.hidden_field :plan_id %>
  <%= f.hidden_field :user_id %>
  <%= f.hidden_field :stripe_card_token %>

  <h4>Change Credit Card</h4>

   <div class="field">
     <%= label_tag :card_number, "Credit Card Number" %>
     <%= text_field_tag :card_number, nil, name: nil %>
   </div>
   <div class="field">
     <%= label_tag :card_code, "Security Code on Card (CVV)" %>
     <%= text_field_tag :card_code, nil, name: nil %>
   </div>

   <div class="field">
     <%= label_tag :card_month, "Card Expiration" %>
     <%= select_month nil, {add_month_numbers: true}, {name: nil, id: "card_month"} %>
     <%= select_year nil, {start_year: Date.today.year, end_year: Date.today.year+15}, {name: nil, id: "card_year"} %>
   </div>

   <%= f.submit "Change Credit Card", :class => "btn btn-primary" %>

<% end %>

[〜#〜]ルート[〜#〜]

App::Application.routes.draw do
  resources :subscriptions
end

[〜#〜]スキーマ[〜#〜]

create_table "subscriptions", :force => true do |t|
  t.integer  "plan_id"
  t.integer  "user_id"
  t.string   "email"
  t.string   "card_name"
  t.string   "exp_month"
  t.string   "exp_year"
  t.string   "card_token"
  t.string   "stripe_customer_token"
  t.string   "last_4_digits"
  t.datetime "created_at",                     :null => false
  t.datetime "updated_at",                     :null => false
end
20
Surge Pedroza

この回答は@TimSullivanからのメモのおかげで更新されました

私は自分のアプリで同じことをしなければなりませんでした。 Stripeはカード番号の更新を許可していません。これには2つのオプションがあります。1)新しいカードを作成し、元のカードを削除します。 2)新しいカードを作成し、それをdefault_cardとして設定して、元のカードのままにします。私は2番目のルートを選びました。

これが私がそれをした方法です:

models/Subscriber.rb

def update_card(subscriber, stripe_card_token)
  customer = Stripe::Customer.retrieve(subscriber.stripe_customer_token)
  card = customer.sources.create(card: stripe_card_token)
  card.save
  customer.default_source = card.id
  customer.save
rescue Stripe::InvalidRequestError => e
  logger.error "Stripe error while updating card info: #{e.message}"
  errors.add :base, "#{e.message}"
  false
end

コントローラー/subscribers_controller.rb

def edit_card
  @subscriber = current_subscriber
end

def update_card
  @subscriber = current_subscriber
  if @subscriber.update_card(@subscriber, params[:stripe_card_token])
    flash[:success] = 'Saved. Your card information has been updated.'
    redirect_to @subscriber
  else
    flash[:warning] = 'Stripe reported an error while updating your card. Please try again.'
    redirect_to @subscriber
  end
end

views/Subscribers/edit_card.html.erb

<%= form_for @subscriber, url: update_card_path, html: { class: 'update_subscriber' } do |f| %>
  <div class='form-group'>
    <%= label_tag        :number, 'Card Number', class: 'col-sm-3 control-label' %>
    <div class='col-sm-9'>
      <%= text_field_tag :number, nil, class: 'form-control', placeholder: 'We accept Visa, MasterCard, AMEX and Discover' %>
    </div>
  </div>

  <div class='form-group'>
    <%= label_tag        :cvc, 'Security Code', class: 'col-sm-3 control-label' %>
    <div class='col-sm-9'>
      <%= text_field_tag :cvc, nil, class: 'form-control', placeholder: 'The code on the back of your card (CVC)' %>
    </div>
  </div>

  <div class='form-group'>
    <%= label_tag        :exp_month, 'Expiration Date', class: 'col-sm-3 control-label' %>
    <div class='col-sm-5'>
      <%= select_month   nil, { add_month_numbers: true }, { id: 'exp_month', class: 'form-control btm-space' } %>
    </div>
    <div class='col-sm-4'>
      <%= select_year    nil, { start_year: Date.today.year, end_year: Date.today.year+15 }, { id: 'exp_year', class: 'form-control btm-space' } %>
    </div>
  </div>

  <div class='form-group'>
    <div class='col-sm-4 col-sm-offset-8'>
      <%= submit_tag 'Update', class: 'btn btn-success btn-block' %>
    </div>
  </div>

  <%= f.hidden_field :stripe_card_token %>
<% end %>

config/routers.rb

match '/edit_card',   to: 'subscribers#edit_card',   via: 'get'
match '/update_card', to: 'subscribers#update_card', via: 'post'

app/js/update_card.js

var subscription;

jQuery(function() {
  Stripe.setPublishableKey($('meta[name="stripe-key"]').attr('content'));
  return subscription.setUpForm();
});

subscription = {
  setUpForm: function() {
    return $('.update_subscriber').submit(function() {
      $('input[type="submit"]').attr('disabled', true);
      if ($('#card_number').length) {
        subscription.updateCard();
        return false;
      } else {
        return true;
      }
    });
  },
  updateCard: function() {
    var card;
    card = {
      number: $('#card_number').val(),
      cvc: $('#card_code').val(),
      expMonth: $('#card_month').val(),
      expYear: $('#card_year').val()
    };
    return Stripe.createToken(card, subscription.handleStripeResponse);
  },
  handleStripeResponse: function(status, response) {
    if (status === 200) {
      $('#subscriber_stripe_card_token').val(response.id);
      return $('.update_subscriber')[0].submit();
    } else {
      $('#stripe_error').text(response.error.message);
      return $('input[type="submit"]').attr('disabled', false);
    }
  }
};

お役に立てれば。

28
Hunter

ここで受け入れられた答えは危険なほど安全に使用できません。 Stripeが推奨するセキュリティを回避します。自分のサーバーは決してクレジットカードの詳細を取得しないでください。

代わりにStripe.jsを使用してカードをStripeに直接渡す (リンク先のRailscastですでに行われている方法と同様)トークンを取得し、トークンに基づいてカードを作成する必要があります。

def update_card(subscriber, stripe_token)
  customer = Stripe::Customer.retrieve(subscriber.stripe_customer_token)
  card = customer.cards.create(card: stripe_token)
  card.save
  customer.default_card = card.id
  customer.save
rescue Stripe::InvalidRequestError => e
  logger.error "Stripe error while updating card info: #{e.message}"
  errors.add :base, "#{e.message}"
  false
end
16
Tim Sullivan

このようにクレジットカードの詳細を更新できます(PHPコード)

  1. まず、カードの詳細と顧客のストライプID(この顧客の作成時にデータベースに保存しておく必要があります)を収集します。
  2. Stripeトークンを作成し、次のようにサーバーに転送します。

     Stripe.setPublishableKey('pk_test_6pRNASCoBOKtIshFeQd4XMUh');
      function stripeResponseHandler(status, response) {
      var $form = $('#payment-form');
    
      if (response.error) {
        // Show the errors on the form
        $form.find('.payment-errors').text(response.error.message);
        $form.find('button').prop('disabled', false);
      } else {
        // response contains id and card, which contains additional card details
        var token = response.id;
        alert('The Token Is: '+token);
        // Insert the token into the form so it gets submitted to the server
        $form.append($('<input type="hidden" name="stripeToken" />').val(token));
        // and submit
        $form.get(0).submit();
      }
    };
    
      jQuery(function($) {
      $('#payment-form').submit(function(event) {
        var $form = $(this);
    
        // Disable the submit button to prevent repeated clicks
        $form.find('button').prop('disabled', true);
    
        Stripe.card.createToken($form, stripeResponseHandler);
    
        // Prevent the form from submitting with the default action
        return false;
      });
    });
    
  3. サーバーでは、次のように詳細を更新できます。

      $customer_id = trim($_REQUEST['cus_select']);     
      $query = "SELECT cus_stripe_id FROM customer_details_tbl WHERE id=$customer_id";      
      $customer_query = mysqli_query($db_conn,$query);
      $row_customer = mysqli_fetch_row($customer_query);
      $cus_stripe_id = $row_customer[0];
    
       Stripe::setApiKey("sk_test_BQokikJOvBiI2HlWgH4olfQ2");
    
       $error = '';
       $success = '';
       try {
        if (!isset($_POST['stripeToken']))
          throw new Exception("The Stripe Token was not generated correctly");
        $customer = Stripe_Customer::retrieve($cus_stripe_id);
        $customer->source = $_POST['stripeToken'];
        $customer->save();
        echo "Card Details Updated Successfully";
       }
       catch (Exception $e) {
        $error = $e->getMessage();
        echo $error;
       }
     }
    

それだ。これにより、既存のカードが新しい詳細で上書きされます。

5
Mudasir Bhat

2015-02-18カードとdefault_card属性がCustomersに返されなくなりました。ここで、sourcesとdefault_sourceをそれぞれ使用する必要があります。 customer.card。*およびcustomer.bank_account。* Webhookの名前がcustomer.source。*になりました。 (他のタイプの支払い元ではなく)顧客にカードが添付されているだけの場合は、古い属性とまったく同じように新しい属性を使用できます。複数のタイプの支払いソースがある場合、ソースリストには異種オブジェクトが含まれ、各ソースのオブジェクト属性をチェックしてその形式を決定できます。古いAPIバージョンは、新しい属性と古い属性の両方を返します。

2
user3462369

したがって、StripeのRubyライブラリには updateメソッド があり、すでにcard.nameがありますが、有効期限にはcard.exp_monthcard.exp_year、すべての引数について updateメソッド を確認してください。

そこに更新カード番号がないことに気付くでしょう。したがって、クレジットカード番号を変更したい場合は、ユーザーに別のカードを作成してもらい、そのカードをデフォルトのクレジットとして使用するように顧客を更新することをお勧めします。カード(チェックアウト カードの作成 および ストライプ内の顧客 の更新= Rubyライブラリドキュメント)。

お役に立てれば

1
user2262149

TimSullivanが提案するようにStripe.jsを使用します。これは、新しいStripeAPI用に更新された彼のコードです。

def update_card(subscriber, stripe_token)
  customer = Stripe::Customer.retrieve({CUSTOMER_ID})
  card = customer.sources.create(card: params[:stripeToken])
  customer.default_source = card.id
  customer.save
rescue Stripe::InvalidRequestError => e
  logger.error "Stripe error while updating card info: #{e.message}"
  errors.add :base, "#{e.message}"
  false
end
1
Stephen