Изменение информации кредитной карты (полоса)
Наконец-то я понял, как реализовать ежемесячную рассылку 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
Ответы
Ответ 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