Подтвердить что ты не робот

Изменение информации кредитной карты (полоса)

Наконец-то я понял, как реализовать ежемесячную рассылку Stripes, используя этот учебник. http://railscasts.com/episodes/288-billing-with-stripe

До сих пор Пользователь может создавать и удалять свою подписку с помощью полосы.

Но как пользователь может изменить свою информацию о кредитной карте после создания подписки

Это мой код с комментариями и вопросами. Пожалуйста, помогите новым рельсам.:)

CONTROLLER

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

MODELS

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

SCHEMA

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
4b9b3361

Ответ 1

Этот ответ был обновлен благодаря примечанию от @TimSullivan

Я должен был сделать то же самое в своем приложении. Stripe не позволяет обновить номер карты. Это дает вам два варианта: 1) создать новую карту и удалить оригинальную карту; и 2) Создайте новую карту, установите ее как карту по умолчанию и оставьте исходную карту. Я выбрал второй маршрут.

Вот как я это сделал:

модели /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

просмотр/подписчики/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 %>

конфигурации /routes.rb

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

приложение /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);
    }
  }
};

Надеюсь, что это поможет.

Ответ 2

Принятый здесь ответ опасно небезопасен для использования. Он защищает безопасность, которую поддерживает 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

Ответ 3

Вы можете обновить данные кредитной карты, подобные этому (PHP CODE)

  • Сначала заберите данные карты и идентификатор полосы клиента (который вы должны были сохранить в своей базе данных при создании этого клиента).
  • Создать маркер 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;
      });
    });
    
  • а на сервере вы можете обновить такие детали:

      $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;
       }
     }
    

Вот и все. Это перезапишет существующую карту новыми деталями.

Ответ 4

2015-02-18 Карты и атрибуты default_card больше не возвращаются клиентам. Теперь вы должны использовать источники и default_source соответственно. Клиент.карты * и customer.bank_account. * Webhooks теперь называются customer.source. *. Если у вас есть карты, прикрепленные к клиентам (в отличие от источников оплаты других типов), вы можете использовать новые атрибуты точно так же, как и старые. Если у вас есть источники оплаты нескольких типов, список источников содержит гетерогенные объекты, и вы можете проверить атрибут объекта каждого источника, чтобы определить его формат. Старые версии API возвращают как новые, так и старые атрибуты.

Ответ 5

Итак, Ruby-библиотека Ruby имеет метод обновления, у вас уже есть card.name, но для даты истечения срока действия вы можете использовать card.exp_month и card.exp_year, проверьте метод обновления для всех аргументов.

Вы заметите, что там нет номера карты обновлений, поэтому мое предложение состояло бы в том, чтобы пользователь создал другую карту, если они хотят изменить номер своей кредитной карты, а затем обновить клиента, чтобы иметь такую ​​карту как кредитная карта по умолчанию (проверьте создать карту и обновить клиента в документации библиотеки ruby ​​ruby).

Надеюсь, что это поможет

Ответ 6

Используйте Stripe.js, как предлагает Тим ​​Салливан. Вот его код обновлен для нового API-интерфейса Stripe.

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