ruby on rails - docs - Cambiar información de la tarjeta de crédito(banda)
stripe checkout docs (6)
2015-02-18 Las tarjetas y los atributos de default_card ya no se devuelven a los clientes. Ahora deberías usar fuentes y default_source respectivamente. Los webhooks customer.card. * Y customer.bank_account. * Ahora se denominan customer.source. *. Si solo tiene tarjetas adjuntas a los clientes (a diferencia de las fuentes de pago de otros tipos), puede utilizar los nuevos atributos exactamente como lo haría con los antiguos. Si tiene fuentes de pago de varios tipos, entonces la lista de fuentes contiene objetos heterogéneos y puede verificar el atributo de objeto de cada fuente para determinar su formato. Las versiones de API más antiguas devuelven los atributos nuevos y antiguos.
Finalmente, descubrí cómo implementar Stripes Monthly Billing usando este tutorial. http://railscasts.com/episodes/288-billing-with-stripe
Hasta ahora, un usuario puede crear y eliminar sus suscripciones con Stripe.
Pero, ¿cómo puede un usuario cambiar su información de tarjeta de crédito una vez que ha creado una suscripción?
Este es mi código con comentarios y preguntas. Por favor, ayuda a los nuevos rieles. :)
CONTROLADOR
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
Los modelos
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
PUNTOS DE VISTA
<%= 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 %>
RUTAS
App::Application.routes.draw do
resources :subscriptions
end
ESQUEMA
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
Así que la biblioteca ruby de Stripe tiene el método de actualización , ya tienes card.name
pero para la fecha de vencimiento puedes usar card.exp_month
y card.exp_year
, revisa el método de actualización para todos los argumentos.
Notará que no tiene un número de tarjeta de actualización allí, por lo que mi sugerencia sería que el usuario cree otra tarjeta si desea cambiar su número de tarjeta de crédito y luego actualizar al cliente para que tenga esa tarjeta como su crédito predeterminado. tarjeta (revise crear tarjeta y actualizar a un cliente en la documentación de la biblioteca Ruby de banda).
Espero que esto ayude
Puede actualizar los detalles de la tarjeta de crédito de esta manera (CÓDIGO PHP)
- Primero recopile los detalles de la tarjeta y la identificación de la franja del cliente (que debe haber guardado en su base de datos mientras crea este cliente).
Cree el token de banda y reenvíe el mismo al servidor de esta manera:
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; }); });
y en el servidor puedes actualizar los detalles así:
$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; } }
Eso es. Esto sobrescribirá la tarjeta existente con los nuevos detalles.
Usa Stripe.js como sugiere Tim Sullivan. Aquí está su código actualizado para la API Stripe más nueva.
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
Esta respuesta ha sido actualizada gracias a la nota de @TimSullivan.
Tuve que hacer lo mismo en mi aplicación. Stripe no permite actualizar el número de tarjeta. Esto te deja con dos opciones: 1) Crear una nueva tarjeta y eliminar la tarjeta original; y 2) Cree una nueva tarjeta, configúrela como la tarjeta_defecto y deje la tarjeta original. Elegí la segunda ruta.
Así es como lo hice:
modelos / suscriptor.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
controladores / suscriptores_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
vistas / suscriptores / 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 / route.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);
}
}
};
Espero que esto ayude.
La respuesta aceptada aquí es peligrosamente insegura de usar . Hace un recorrido final alrededor de la seguridad que Stripe alienta. Su propio servidor nunca debe obtener los datos de la tarjeta de crédito.
En su lugar, debe usar Stripe.js para pasar la tarjeta a Stripe directamente (de manera similar a como se hace en el Railscast al que está vinculado) y recuperar un token, luego crear la tarjeta basada en el token.
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