Subscriptions in stripe - ruby-on-rails

I've read this https://stripe.com/docs/tutorials/subscriptions but don't really understand the idea of subscriptions in respect to implementation.
What I need is being to charge the user but the amount of charge is to be calculated by myself because I have a special algorithm for it. So this code:
# create a plan - once!
Stripe::Plan.create(
:amount => 2000,
:interval => 'month',
:name => 'Amazing Gold Plan',
:currency => 'cad',
:id => 'gold'
)
# every month? or also once?
maybe_customer = Stripe::Customer.retrieve(....)
unless maybe_customer
customer = Stripe::Customer.create(
:card => token,
:plan => "gold",
:email => "payinguser#example.com"
)
end
When (how often) do I have to run it: only once or every month (:interval => 'month')?
If every month, I'll run it as a cron task. But how to get the user to enter in their credit card details? Or do they have to enter them in only the first time, then I save them and then will be able to re-use them?
UPDATE:
Since it's a subscription, it's to occur automatically. Does that mean that it's completely automatic for the user? Or do they have to enter their card details into the pop up from Stripe once and from that moment on it'll become automatic for the user, meaning they won't have to enter their bank card details anymore, they will be charged automatically by stripe each month later?
How do charge the user zero cents as a monthly pay if some (my) condition is true and using account_balance? From this https://support.stripe.com/questions/metered-subscription-billing I don't understand how to do that.
I don't see any difference between a subscription and just charging a customer like if it were the normal payments. If both cases I have to run a code once a month on the server. What's the difference?

Sorry, but the only thing I could understand clearly from your question was that you need to know how to execute one-time payments rather than proper subscriptions.
Reading the link you've shared, I've gathered that you should be able to set an interval_count option for the number of months (or intervals) after which the customer is charged. So setting interval_count to 0 should make the payment happen only once.
Also, this is from the same page:
Customer objects can also store a credit card, which is how they'll be
billed later on.
In other words, yes - the customer enters his/her card details the first time. You can (optionally ?) save the card info in the Customer object.

Related

How to decrease db attribute value over time with Rails?

I'm creating a credit-based application, where the user puts credit in his account and the credit decreases over time based on user's active services.
For example:
User deposits U$ 30 in his account
User accquires a service that costs U$ 60/month
His credits will decrease over time, so in the second day of use, user's credit will be U$ 28 (U$ 30 - U$ 2 from the accquired service)
User will be able to see his current balance any time
I realize that I can use cron jobs to decrease the account balance, but it's gonna make a lot of requests to database and I am sure there must be better ways to do that.
How can I do it?
One way to achieve this is using a column and a callback e.g.
You will need to add a column say last_deducted_on as date then in the show action of account_balance you can have a before_action like
before_action :deduct_amount_if_applicable, only: :show
private
def deduct_amount_if_applicable
if current_user.deduction_applicable?
amt = (Date.today - account.last_deducted_on).to_i * amount_to_be_deducted
account.update_attribute(:total, (account.total - amt))
# update column with today's date
end
end
Although it will work, I suggest to use scheduler as it is a scheduled job and needs to be done every day, there are ways to reduce queries e.g. using update_all, etc. depending on use case but still the better option. In case if you have transaction history and you show date of transaction, above method will piss of user if he will open his account days later and suddenly huge amount is deducted.

Stripe Account Transfer

I am working on transfer amount from one account to another account using stripe.I have enough amount in my test mode but i am getting the insufficient fund error.I am working on since 15 days but i am not able to find any feasible solution for that.
The code which i am using for transfer the amount is as:
#pay =
Stripe::Transfer.create({
amount: #offer_transaction.amount.to_i,
currency: 'hkd',
destination: #offer_transaction.transfer_payment_in,
description: 'Transfer for test#example.com'
},
{
:stripe_account => #user.stripe_connect_account_id
})
Each Stripe account has two different types of balances: available (meaning funds are available to be transferred out to an external bank account) and pending (meaning funds are not yet available).
When you create a charge and new funds are added, they're initially added to the pending balance, and only become available after a delay.
You can check an account's balance with the "retrieve balance" API call. In test mode, you can also create charges with this card number: 4000 0000 0000 0077 and the funds from the charge will be immediately available.

Applying monthly referral discounts to a subscription fee

Description of functionality:
So I have a subscription based website that has two plans: Monthly and yearly. A monthly subscription is charged a monthly fee every month, while a yearly subscription is charged a one-time cumulative fee of 10 months, each year. ($29/mo and $290/yr)
I have 10% recurring referral discounts that are applied each month, for every active member who was referred (100% max). So if Bob signs up for a monthly subscription in October, and throughout the next month refers 5 people who sign up, he should have a 50% discount accumulated. This will be applied to his subscription fee in November, which will result in $14.50 for that month. But assume one of his referrals cancels in November. This will drop his discount for December by 10%, which will give him a 40% discount, with 4 active referrals, resulting in $17.40 for December.
Example of working code:
If every one of Bob's referrals is monthly, this is fairly simple to apply with webhooks. An amount is just deducted from Bob's current balance every time a successful payment goes through, if the user connected to that payment is one of Bob's referrals.
# Webhooks Controller
def payment_success
referred_user = User.find_by_customer_id(#subscription.customer.reference)
if referring_user = User.find_by_affiliate_code(referred_user.referral_code)
balance = referring_user.subscription.balance_in_cents
referring_user.subscription.adjustment({"amount_in_cents"=>"-290","memo"=>"Balance adjusted for referring #{referred_user.email}. Payment for referral was successful."})
referring_user.subscription.save
end
head :ok
end
This sends a request to Chargify, the payment processor I'm using, to adjust the balance accordingly.
My real problem:
It isn't this straightforward, though, when one of Bob's referrals is a yearly user.
Since the yearly subscription is a one-time payment, the payment_success webhooks aren't coming through every month, which means 10% of Bob's subscription can't be deducted each month from this yearly user's active referral.
I thought of just setting Bob's plan price to 10% less than standard, instead of adjusting the balance each month. This would require 9 different plans, though, since the plan price directly refers to a Plan object on Chargify, which points to its price attribute. That means that there would need to be a 90%_monthly_plan, a 80%_monthly_plan, and so on, which all live on the Chargify servers. This seems overly complex, and I also wouldn't be surprised if it caused other issues I'm not even considering at this point.
My current (unsatisfactory) solution:
So instead I decided to just create a scheduler on my server that is created when a yearly user signs up, and it fires every month.
I'm using rufus-scheduler for this. One important thing to note - Schedules are destroyed when the server is restarted, so I'm creating schedule records, and an initializer goes through these records and creates these schedules every time the server restarts.
# modified Webhooks Controller
def payment_success
referred_user = User.find_by_customer_id(#subscription.customer.reference)
if referring_user = User.find_by_affiliate_code(referred_user.referral_code)
balance = referring_user.subscription.balance_in_cents
referring_user.subscription.adjustment({"amount_in_cents"=>"-290","memo"=>"Balance adjusted for referring #{referred_user.email}. Payment for referral was successful."})
referring_user.subscription.save
if #subscription.product.handle == 'yearly'
schedule = ReferralSchedule.create(
type_of: "yearly discount",
referred_user_id: referred_user.id,
referring_user_id: referring_user.id,
time_to_execute: "30.41d"
)
ReferralScheduler::create_yearly_discounts_schedule(schedule)
end
end
head :ok
end
And the module handling the schedule creation:
module ReferralScheduler
def self.create_yearly_discounts_schedule(schedule)
referred_user = User.find(schedule.referred_user_id)
referring_user = User.find(schedule.referring_user_id)
# first_date is calculated to be the first date in the future, that the scheduler should run.
first_date = Time.now + (30.41-(DateTime.now - schedule.created_at.to_datetime).fdiv(30.41)%1*30.41).days
scheduler = Rufus::Scheduler.new
scheduler.every schedule.time_to_execute, first: first_date , last_at: (schedule.created_at+12.months) do
if referring_user && referred_user.subscription_status == :active
balance = referring_user.subscription.balance_in_cents
referring_user.subscription.adjustment({"amount_in_cents"=>"-290","memo"=>"Balance adjusted for referring #{referred_user.email}. Referral is still active."})
referring_user.subscription.save
end
end
scheduler.at (schedule.created_at+12.months) do
schedule.destroy!
end
end
end
And the initializer:
require 'rufus-scheduler'
ReferralSchedule.where(type_of: "yearly discount").each do |schedule|
ReferralScheduler::create_yearly_discounts_schedule(schedule)
end
I really hate using this method, as it doesn't seem very clean. It has also already screwed up my local server when I tried to run it at shorter intervals.
I also thought about using rake tasks and/or Grunt to perform this, but I have very limited knowledge on each of these, and I'm not sure if they will necessarily be easier/better solutions.
Any ideas?
One option might be to use the upcoming_renewal_notice webhook on Bob's subscription as a trigger to go see how many referrals he has made that are on annual plans, and apply any additional discounts.
https://docs.chargify.com/webhooks
upcoming_renewal_notice - A subscription set to renew within 3 days

Creating a subscription in Stripe - I'm confused

I use stripe subscriptions for my users with one plan for, say, $10 per month for 100 API requests and that's a standard price. However, if the user has used 150 API requests, I charge them $10 + $3. For 200 and more requests it's $10 + $7.
Say, I've subscribed the user on October 9th. On November 9th the webhook event invoice.created will be called by stripe. So if the user has used 150 API requests, I have to add $3 more to the basic price (I can do that only within 1 hours according to Stripe documentation https://support.stripe.com/questions/metered-subscription-billing).
if even.type == 'invoice.created'
Stripe::InvoiceItem.create(
customer: stripe_customer_id,
invoice: event.data.object.invoice
amount: 300,
currency: 'usd',
description: 'additional price'
)
The questions:
Will the event invoice.created, indeed, be called on November 9th for the first time?
Will that additional price of $3 be added to the current invoice of $10 for October 9th-November 9th or will it be added to the future invoice for November 9th-December 9th? From the documentation it's not clear.
How do I add metadata to the original invoice of $10? I can add metadata to the additional invoice but in case the user has used less 100 API request I don't have to create the additional invoice at all, so I can't rely to the additional invoice.
It says
Create any invoice items before your customer is subscribed to the
plan, and then create the subscription via an update customer
subscription call.
but I subscribe the user once and forever on October 9th! How can I create an InvoiceItem before or on that (on October 9th) date if one month hasn't passed yet, and thus it's not known how many API calls the user makes (on October 9th the user has made, obviously, zero API calls)? I can only create InvoiceItems in 30 days because it's when I know how much to charge them on top on the $10! On October 9th I don't know that. Don't I understand anything?
Each time an invoice is created, you get the event invoice.created on your webhook. So when you subscribe a customer to a monthly plan on the 9th of November, you will get this event on the 9th of November, on the 9th of December, on the 9th of January, etc.
The first invoice for a subscription (generated when you create a subscription) is always closed immediately, so it is not possible to add an invoice item at that point. If that's something you want to do (for a setup fee for example) you need to create the invoice item before creating the subscription. That way it would get added automatically to the first invoice created when subscribing your customer.
In your case, you want to add fees to the next invoice based on the number of API requests your customer made during the month that just ended. So in the invoice.created event you need to detect whether it's a new month starting or the first one. If it's a new month, you then need to decide whether you have to add an Invoice Item to the user or not (based on the number of API requests).
You can't add metadata to the previous invoice from the month before. You just need to add the invoice item to the current invoice (for the month that is starting) and put a description indicating that the extra line item is for the consumption for the previous month.

Rails + Sessions: Safe to store partial credit card info in session?

I am working on a checkout and I want it so that on the "order summary" page, the user will see their credit card info like Card Number: ************1111, Expiration Date: 12/15. I'm not saving the credit card info since that's against standards, so I'm thinking I could save the last 4 digits of the user's credit card info + the expiration date in my session when the user inputs it on the billing information page so that on the "order summary" page it'll show.
Is this against e-commerce standards?
Do it. You are allowed to print "Card Number: ******1111" on a piece of paper, and that's permanent and leakable. Hence you are allowed to store only those 4 characters in your database, and print them at need.
The expiration date, however, IS sensitive (BC it participates in authorization), so lose it.
(2 years working with payment gateways experience here...)

Resources