So I have a rails app where I'm selling subscriptions to access content. For users in NJ, I have to charge them 7% sales tax. Everywhere else is 0. So when they register an account with Devise, I record their state.
Then in my SubscriptionsController.rb, I check to see if they live in NJ:
data = if current_user.home_state == "NJ"
subscription_params.merge(tax_percent: 7)
else
subscription_params
end
#subscription = ::Subscription.new(data)
When the subscription gets created, the subscription table gets updated properly. I also assumed that when the user makes a purchase this tax_percent would also hit Stripe's API, but it doesn't.
So I tried adding this to the subscription creation form:
<%= f.hidden_field :tax_percent %>
and it does hit Stripe's API, but hits as tax_percent: '', which is null.
So I can always perform a logic check like this:
<% if current_user.home_state == "NJ" %>
<%= hidden_field :tax_percent, :value => '7' %>
<% end %>
But then I'm exposing the value to the client, which can be manipulated.
What's the best 'rails' way to submit this value to Stripe's API?
It's a bit hard to tell what's going on based on the code-sample you've provided, but ultimately you want to set the tax-rate on individual users when you Create the Subscription [1].
If you're going to be doing one-off payments, you'll need to also store that information somewhere else on the Customer record. I might recommend you utilize the metadata-parameter [2] of the Customer record. You can set it by making an Update Customer [3] API Request. Then, when you're making a charge [4], you'll want to multiply it by whatever tax coefficient you've stored.
Another (probably better) approach, would be to create a pending invoice item [5] for the one-time purchase (without tax being included). Then create an Invoice [6] with the tax_percent-parameter being populated. And finally, pay the Invoice [7]. This will make a trackable record of purchases made with line-items for their tax percent kept separate.
Hope that helps!
[1] https://stripe.com/docs/api#create_subscription
[2] https://stripe.com/docs/api#metadata
[3] https://stripe.com/docs/api#update_customer
[4] https://stripe.com/docs/api#create_charge
[5] https://stripe.com/docs/api#create_invoiceitem
[6] https://stripe.com/docs/api#create_invoice
[7] https://stripe.com/docs/api#pay_invoice
Related
I have two subscription plans in my Ruby on Rails application. I use stripe webhook to email to customer when subscription has been created. In the email I want to store data about subscription (and plan) details e.g. when trial_end and plan name or price.
def webhook
stripe_event = Stripe::Event.retrieve(params[:id]) #retrieving Event ID
if stripe_event.type == "customer.subscription.created" #checks if retrieved Event type subscription is created
stripe_customer_token = stripe_event.data.object.customer # Get Customer ID
customer = Stripe::Customer.retrieve(stripe_customer_token) #here I'm able to retrieve Customer data e.g. customer.email
subscription = customer.subscriptions.first.id #according to documentation I need to retrieve Subscription by supplying its ID. I can retrieve Subscription, but don't understand how to retrieve its data, like: subscription.trial_end
UserMailer.customer_subscription_created(customer.email).deliver #this works well
UserMailer.customer_subscription_created(subscription.trial_end).deliver #this does not work
end
end
I have retrieved Subscription of my Customer. When I retrieve customer I can access my customer data like: customer.email I assumed I would be able to do the same when I retrieve Subscription: subscription.trial_end, but this gives me an error. How can I access Subscription data?
Besides when I change plan of a Subscription I do it like so and it works:
def change_user_plan(customer_id, subscription_id)
customer = Stripe::Customer.retrieve("#{customer_id}")
subscription = customer.subscriptions.retrieve("#{subscription_id}")
subscription.plan = 2
subscription.save
end
Here is link to Stripe API to retrieve Subscription
You are correct, you are able to do what you are trying to do. Once you have your subscription, subscription.trial_end works. I just tested it:
2.1.6 :013 > customer = Stripe::Customer.retrieve("#{customer_id}")
=> #<Stripe::Customer:0x3fcd1ed0a630 id=...> JSON: { ... }
2.1.6 :014 > subscription = customer.subscriptions.retrieve("#{subscription_id}")
=> #<Stripe::Subscription:0x3fcd1ecae574 id=...> JSON: { ... }
2.1.6 :015 > subscription.trial_end
=> 1438387199
The problem is this line:
subscription = customer.subscriptions.first.id
You are saving the subscription id itself. You need to do:
subscription = customer.subscriptions.first
to save the whole subscription. Also, you can use subscriptions.retrieve to supply the id for retrieval (as you are doing in your second code example).
I'm working on cleaning up my app a little to gain better performance. Rather then having about 5 lines of stuff I want to shorten stuff down. Current in my controller I have;
# this pretty much talks with Stripe and grabs our customer token or account id
customer = Stripe::Customer.retrieve(current_user.stripe_customer_token)
# this grabs the stripeToken card info and creates the credit card
customer.cards.create(:card => params[:stripeToken])
customer.subscriptions.create(:plan => 'subscriber')
customer.save
I wanted to shorten stuff up and not sure if this would be a good idea;
customer = Stripe::Customer.retrieve(current_user.stripe_customer_token)
customer.cards.create(:card => params[:stripeToken]) unless customer.cards.present? customer.subscriptions.create(:plan => 'subscriber').save
Would that above work? I've got errors, maybe I'm missing something.
This is technically the same number of lines but a bit more concise in my opinion (untested):
Stripe::Customer.retrieve(current_user.stripe_customer_token).tap do |customer|
customer.cards.create(card: params[:stripeToken])
customer.subscriptions.create(plan: :subscriber)
end.save
I am working on a small app that allows for users to add a product (or subscription) to their cart. Upon creating their account, the new user is sent to a "bundle" page where it asks if they would like to add a different subscription to a different product altogether for a bundled price.
Here is where I am stuck: Upon submitting the user's credit card info I get slightly "lost in translation" when trying to setup the bundle pricing to submit to Authorize.net (I understand how to authnet, not the question here).
Here is what I have so far:
current_order.products.includes(:client).each do |product|
transaction = current_order.submit_order_to_authnet(product)
if transaction.result_code == 'Ok'
new_group = Group.create!(:name => "#{current_user.full_name} #{product.title}", :type => 'school', :start_date => Time.now, :status => 'active', :site_id => 1)
primary = session[:primary_product_id].eql?(product.id) ? true : false
# Add subscription to Group
new_group.add_subscription(product, current_order, transaction.subscription_id, 'active', primary)
# Add Subscription to CurrentOrder
current_order.subscriptions << new_group.subscriptions.last
# Add user to NewGroup
current_user.groups << new_group
# Create New Group Admin
new_group.group_admins.create(:user_id => current_user.id)
# Send success email
OrderMailer.checkout_confirmation(current_user).deliver
else
errors << transaction.result_code
end
end
I am trying to figure out the best solution when it comes to looping through each product in the users current_order because the second subscription in the users cart is the subscription that gets the discount applied too. I know I can write something like this:
current_order.products.includes(:client).each do |product|
if current_order.products.many? and product == current_order.products.last
# run discount logic
else
# continue with authnet for single subscription
end
end
But I am just not sure if that is a best practice or not. Thoughts?
So the only subscription that doesn't get discounted is the first one? Why not write it like this:
current_order.products.includes(:client).each do |product|
if product == current_order.products.first
# continue with authnet for single subscription
else
# run discount logic
end
end
Has anyone had success in resubscribing an email address after being unsubscribed via the Campaign Monitor API.
I ask as i want to keep a list of Active User's email addresses in my CM Active List. When they are suspended they get removed, when they join or pay their fees before getting deleted they are (re)subscribed.
Looking at the Rails API docs:
# File lib/campaign_monitor.rb, line 241
def remove_subscriber(email)
response = #cm_client.Subscriber_Unsubscribe("ListID" => #id, "Email" => email)
Result.new(response["Message"], response["Code"].to_i)
end
# File lib/campaign_monitor.rb, line 445
def unsubscribe(list_id)
response = #cm_client.Subscriber_Unsubscribe("ListID" => list_id, "Email" => #email_address)
Result.new(response["Message"], response["Code"].to_i)
end
On the CM website to move an email in the subscriber list to the active list you need to confirm you have permission to resubscribe them, can anyone say for sure that this applies to the API too?
I've just found the Subscriber.AddAndResubscribe method, undocumented in http://campaignmonitor.rubyforge.org/
I'd like some advice on how I should synchronize a list of email addresses on 11k users against an external mailing list program, in this case Mailchimp.
Normally the way I'd do this is simply to have an :after_save callback, to send a single update to the external api.
But already each hour, a rake task is run to update a property on every user in the database. If I simply did that, every hour, the the poor mailchimp API would get be hit 11,000 times.
What's the most efficient, simple way to do this, to check only if a single attribute you're watching has changed from what it was before the save?
If there's a variable that persists across the transaction lifecycle I would simply do something like this, where I check if the value has changed, and if it's different execute come other code.
class User
:before_save :store_old_email
:after_save :sync_with_chimp
def store_old_email
$ugly_of_global_variable_to_store_email = user.email
end
:sync_with_chimp
if $ugly_of_global_variable_to_store_email != user.email
//update_mail_chimp_api
end
end
end
I've checked the rails api here, and I'm still slightly unclear on how I should be doing this.
Would you use the dirty? class here to do this?
This is the way I went with in the end.
It turns out Rails gives you loads of handy callbacks in the dirty to do this.
Any suggestions on how to make this code less repetitive wold be gratefully received.
def update_mailchimp(optin)
# Create a Hominid object (A wrapper to the mailchimp api), and pass in a hash from the yaml file
# telling which mailing list id to update with subscribe/unsubscribe notifications)
#hominid = Hominid.new
client_site_list_id = YAML.load(File.read(RAILS_ROOT + "/config/mailchimp.yml"))
case optin
when 'subscribe_newsletter'
logger.debug("subscribing to newsletter...")
"success!" if #hominid.subscribe(client_site_list_id['client_site_to_mailchimp_API_link'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
when 'unsubscribe_newsletter'
logger.debug("unsubscribing from newsletter...")
"success!" if #hominid.subscribe(client_site_list_id['client_site_to_mailchimp_API_link'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
when 'subscribe_monthly_update'
logger.debug("subscribing to monthly update...")
"success!" if #hominid.subscribe(client_site_list_id['monthly_update'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
when 'unsubscribe_monthly_update'
logger.debug("unsubscribing from monthly update...")
"success!" if #hominid.unsubscribe(client_site_list_id['monthly_update'], email, {:FNAME => first_name, :LNAME => last_name}, 'html')
end
end
# Keep the users in sync with mailchimp's own records - by only firing requests to the API if details on a user have changed after saving.
def check_against_mailchimp
logger.info("Checking if changes need to be sent to mailchimp...")
if newsletter_changed?
logger.info("Newsletter changed...")
newsletter ? update_mailchimp('subscribe_newsletter') : update_mailchimp('unsubscribe_newsletter')
end
if monthly_update_changed?
logger.info("update preferences changed...")
monthly_update ? update_mailchimp('subscribe_monthly_update') : update_mailchimp('unsubscribe_monthly_update')
end
end
you could change your users model to an active resource instead of active record and just use mailchimps api as your db for users
this is an older post about active resource but might get you started down the right path
http://www.therailsway.com/2007/9/3/using-activeresource-to-consume-web-services