Stripe::Customer.create not attaching the payment method to customer - ruby-on-rails

I am creating a setup intent and receiving the payment method's id from it. Then I am creating a customer using the following code
customer = Stripe::Customer.create({
email: current_user.email,
description: "Customer for subscription",
payment_method: params[:payment_method]
})
It is returning the following response
{
"id": "cus_IZmhg4VhIwFUBI",
"object": "customer",
"address": null,
"balance": 0,
"created": 1608037176,
"currency": null,
"default_source": null,
"delinquent": false,
"description": "Customer for subscription",
"discount": null,
"email": "customer#example.com",
"invoice_prefix": "76BF0C5E",
"invoice_settings": {
"custom_fields": null,
"default_payment_method": null,
"footer": null
},
"livemode": false,
"metadata": {
},
"name": null,
"next_invoice_sequence": 1,
"phone": null,
"preferred_locales": [
],
"shipping": null,
"tax_exempt": "none"
}
The problem is, it is not attaching the payment method to the customer, when I try to create a subscription using the customer object, it returns the following error:
Stripe::InvalidRequestError (This customer has no attached payment source or default payment method.):
But when I look in the dashboard, the payment method is already attached with the customer

The payment_method is attached, and you can list them for the customer. Then, you need to set explicitly the invoice_settings.default_payment_method for the Customer, which is what will be used for the subscription creation.

Inspired by the #Nolan's answer, I have fixed the issue by passing payment id to invoice_settings.default_payment_method while customer creation. Following is the code snippet:
customer = Stripe::Customer.create({
email: current_user.email,
description: "Customer for subscription",
payment_method: params[:payment_method],
invoice_settings: {
default_payment_method: params[:payment_method]
}
})

Related

How to write API response example for a related entity in Phoenix swagger?

I'm building a REST API in Elixir/Phoenix and documenting the endpoints via Phoenix Swagger.
I have an entity called users which has the following code inside swagger_definitions in user_controller.ex
def swagger_definitions do
%{
User:
swagger_schema do
title("User")
description("A user in the application")
properties do
first_name(:string, "First name")
last_name(:string, "Last name")
email(:string, "Email")
role(:string, "User role")
end
example(%{
first_name: "Rahul",
last_name: "Sharma",
email: "rahul.sharma#example.com",
role: "student"
})
end,
Users:
swagger_schema do
title("Users")
description("All users in the application")
type(:array)
items(Schema.ref(:User))
end,
}
end
Now, there's another controller session_controller.ex which returns the many-to-many related users to a session when calling the single session GET endpoint. Here's an example of the response:
{
"end_time": "2022-02-02T11:30:00Z",
"id": 1,
"start_time": "2022-02-02T11:00:00Z",
"users": [
{
"email": "janedoe#example.com",
"first_name": "Jane",
"id": 1,
"last_name": "Doe",
"role": null,
},
{
"email": "johndoe#example.com",
"first_name": "John",
"id": 2,
"last_name": "Doe",
"role": null,
}
]
}
Now, when I'm trying to document the above API response using the Swagger example within session_controller.ex, the example isn't coming up correctly in Swagger UI:
SessionWithUser:
swagger_schema do
title("SessionWithUser")
properties do
session_id(:integer, "Session ID")
start_time(:timestamp, "Session start time")
end_time(:timestamp, "Session finish time")
users(Schema.ref(:Users), "Users attending the session")
end
example(%{
session_id: 1,
start_time: "2022-02-02T11:00:00Z",
end_time: "2022-02-02T11:30:00Z",
users: Schema.items(:User)
})
end
What am I doing wrong?

Stripe retrieve the good price ID

I setup my shop with Stripe. You can buy it with the good product and with different sizes. It works well until I have to sent an email to the seller with some informations like the name of the product bought, the size of the product (product.nickname), the customer information and so on. My problem is I can't get this 'nickname'.
As I understand in Stripe, you have some Products, which can have different Prices. For me, I have a product with 3 prices. Each price has his own ID and a 'label' (according to Stripe called 'nickname' as I saw in the request). The problem came when I want to retrieve this ID to get the specific nickname (the name if the size). For some reason, the ID returned for the selected product is not the same as the ID from Stripe Dashboard. And each time I got a new purchase, this returned ID change.
In my WebhooksController in def create:
case event.type
when 'checkout.session.completed'
session = event.data.object
#order = Stripe::Checkout::Session.retrieve({ id: session.id, expand: ["line_items", "customer"]})
OrderMailer.order_mail(#order).deliver
end
render json: { message: 'success' }
In my order_mail.html.erb:
<% #order.line_items.data.each do |line| %>
<%= line %>
<% end %>
Can someone explain me why the line_item ID returned in the webhook is not the same as the Stripe dashboard ID? And how can I get and display the nickname of the price selected in my mail?
here is what I got for the <%= line %>
{ "id": "li_1K41JPFE4oPSz5YO98K2r2CW", "object": "item", "amount_subtotal": 4000, "amount_total": 4000, "currency": "eur", "description": "Soleil Levant", "price": { "id": "price_1K41JPFE4oPSz5YORWdXXGuT", "object": "price", "active": false, "billing_scheme": "per_unit", "created": 1638874459, "currency": "eur", "livemode": false, "lookup_key": null, "metadata": { }, "nickname": null, "product": "prod_KjUHP8uALE6aZI", "recurring": null, "tax_behavior": "unspecified", "tiers_mode": null, "transform_quantity": null, "type": "one_time", "unit_amount": 4000, "unit_amount_decimal": "4000" }, "quantity": 1 }
If I cUrl the right price:
https://api.stripe.com/v1/prices/price_1JxC8kFE4oPSz5YOc391IZ9I\
-u sk_test_51JbmGvFE4oPSz5YOsl0JTTEi0quapEwPBXQsQRbRXPdr38hSiyVDPs9LnkH4nHCGXqwoYjOTnHoH6FtIC4EP32pr00KHIxFlLp:
I got this:
{
"id": "price_1JxC8kFE4oPSz5YOc391IZ9I",
"object": "price",
"active": true,
"billing_scheme": "per_unit",
"created": 1637247786,
"currency": "eur",
"livemode": false,
"lookup_key": null,
"metadata": {
"nickname": "S"
},
"nickname": "S",
"product": "prod_KcR0HgpfzldOj8",
"recurring": null,
"tax_behavior": "unspecified",
"tiers_mode": null,
"transform_quantity": null,
"type": "one_time",
"unit_amount": 4000,
"unit_amount_decimal": "4000"
}
What you are doing should work:
First, create a Price with nickname: "foobar", let’s say its ID is "price_abc".
Then, create a Checkout Session where you set line_items[0].price: "price_abc".
Later, you retrieve the Checkout Session with expand: ["line_items"]. If you look into checkout.line_items.data[].price, you will find an object that contains what you are looking for: { id: "price_abc", nickname: "foobar", … }. Note that you can see the structure of the line_items.data object in the Stripe documentation here.
So you need to double check that you are using the correct price ID when creating the Checkout Session, and that you are looking at checkout.line_items.data[].price to find the id and nickname of the price.

When I Query an Account with Type "Cost of Goods Sold" how do I return ExpenseAccountRef?

I currently need two more required fields to Create a NonInventory Item: ExpenseAccountRef.value and ExpenseAccountRef.name
I have issued a Query for AccountType = 'Cost of Goods Sold'
Does Account.Id = ExpenseAccountRef.value?
Does Account.Name = ExpenseAccount.name?
Use Account.Id and Account.Name from that object for
ExpenseAccountRef.value and ExpenseAccountRef.name, respectively.
Request URL:
GET /v3/company/4620816365171303340/query?query=select * from Account where AccountType = 'Cost of Goods Sold'&minorversion=59
Content type:text/plain
Production Base URL:https://quickbooks.api.intuit.com
Sandbox Base URL:https://sandbox-quickbooks.api.intuit.com
Query:
select * from Account where AccountType =
'Cost of Goods Sold'
Returns:
{
"QueryResponse": {
"Account": [
{
"Name": "Cost of Goods Sold",
"SubAccount": false,
"FullyQualifiedName": "Cost of Goods Sold",
"Active": true,
"Classification": "Expense",
"AccountType": "Cost of Goods Sold",
"AccountSubType": "SuppliesMaterialsCogs",
"CurrentBalance": 0,
"CurrentBalanceWithSubAccounts": 0,
"CurrencyRef": {
"value": "USD",
"name": "United States Dollar"
},
"domain": "QBO",
"sparse": false,
"Id": "80",
"SyncToken": "0",
"MetaData": {
"CreateTime": "2021-05-01T10:36:04-07:00",
"LastUpdatedTime": "2021-05-01T10:36:04-07:00"
}
},
{
"Name": "MyJobs_test",
"SubAccount": false,
"FullyQualifiedName": "MyJobs_test",
"Active": true,
"Classification": "Expense",
"AccountType": "Cost of Goods Sold",
"AccountSubType": "CostOfLaborCos",
"CurrentBalance": 0,
"CurrentBalanceWithSubAccounts": 0,
"CurrencyRef": {
"value": "USD",
"name": "United States Dollar"
},
"domain": "QBO",
"sparse": false,
"Id": "91",
"SyncToken": "0",
"MetaData": {
"CreateTime": "2021-07-13T14:31:01-07:00",
"LastUpdatedTime": "2021-07-13T14:31:01-07:00"
}
}
],
"startPosition": 1,
"maxResults": 2
},
"time": "2021-07-15T13:21:57.267-07:00"
}
Info for ExpenseAccountRef from the official Intuit Developer Documentation
"Reference to the expense account used to pay the vendor for this item.
Must be an account with account type of Cost of Goods Sold.
Query the Account name list resource to determine the appropriate Account object for this reference.
Use Account.Id and Account.Name from that object for ExpenseAccountRef.value and ExpenseAccountRef.name, respectively."
https://developer.intuit.com/app/developer/qbo/docs/api/accounting/most-commonly-used/item#create-an-item
Yep, you've got it right!
As the documentation you quoted says:
"Use Account.Id ... for ExpenseAccountRef.value
and:
"Account.Name ... for ExpenseAccountRef.name"
Your questions here are correct statements!
Does Account.Id = ExpenseAccountRef.value?
Does Account.Name = ExpenseAccount.name?
You answered your own questions. Woohoo! Go you! :-)

Stripe Webhook firing but Stripe event method not running

Using the stripe events gem I am trying to update a Stripe subscription on the event unsubscribe. My events are not firing even though they are receiving the webhook.
I am running my endpoint on ngrok and using the stripe-events gem. I have installed the stripe cli so I can see that the webhook events are firing.
My thinking is that there is a problem with the code I am trying to use
#user = User.find_by_stripe_id(event.data.object.customer) however I got this code from a thread on GoRails. Chris Oliver said that it looked correct and I have repurposed it for my app so that makes me think it might be something else.
# config/initializers/stripe_events.rb
Stripe.api_key = Rails.application.credentials.stripe_publishable_key
Stripe.api_key = Rails.application.credentials.stripe_signing_secret
StripeEvent.configure do |events|
events.subscribe "customer.subscription.updated" do |event|
#user = User.find_by_stripe_id(event.data.object.customer)
logger.info "Processing the request..."
if DateTime.now >= #user.subscription_end_date
logger.info "if statement is running..."
#user.update_attribute(subscribed: false)
#user.save!
end
end
end
I am not sure if this is needed but here is the method that triggers the webhook. I have added the DateTime.now-1 for testing if the webhook so that it simulates an expired subscription.
# app/controllers/subscriptions_controller.rb
def destroy
if Rails.env.production?
Stripe.api_key = Rails.application.credentials.stripe_live_api
else
Stripe.api_key = Rails.application.credentials.stripe_api_key
end
customer = Stripe::Customer.retrieve(current_user.stripe_id)
customer.subscriptions.retrieve(current_user.stripe_subscription_id)
Stripe::Subscription.update(current_user.stripe_subscription_id,:cancel_at_period_end => true)
##current_user.update(subscription_end_date: Time.at(customer.subscriptions[:data].first[:current_period_end]))
current_user.update(subscription_end_date: DateTime.now-1)
redirect_to root_path, notice: "Your subscription has been cancelled"
end
I tested the response from the stripe webhook
{
"object": {
"id": "sub_FqLLZZ4pKhlM0y",
"object": "subscription",
"application_fee_percent": null,
"billing": "charge_automatically",
"billing_cycle_anchor": 1568957293,
"billing_thresholds": null,
"cancel_at": 1571549293,
"cancel_at_period_end": true,
"canceled_at": 1568957302,
"collection_method": "charge_automatically",
"created": 1568957293,
"current_period_end": 1571549293,
"current_period_start": 1568957293,
"customer": "cus_FqLLXYHyVl7mJq",
"days_until_due": null,
"default_payment_method": null,
"default_source": null,
"default_tax_rates": [
],
"discount": null,
"ended_at": null,
"items": {
"object": "list",
"data": [
{
"id": "si_FqLLngQNhxl5p4",
"object": "subscription_item",
"billing_thresholds": null,
"created": 1568957293,
"metadata": {
},
"plan": {
"id": "plan_FYHrCVDopLPS37",
"object": "plan",
"active": true,
"aggregate_usage": null,
"amount": 2900,
"amount_decimal": "2900",
"billing_scheme": "per_unit",
"created": 1564792787,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
},
"nickname": "Uproar Basic",
"product": "prod_FYHpmwiftJrqpC",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": null,
"usage_type": "licensed"
},
"quantity": 1,
"subscription": "sub_FqLLZZ4pKhlM0y",
"tax_rates": [
]
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/subscription_items?subscription=sub_FqLLZZ4pKhlM0y"
},
"latest_invoice": "in_1FKefBJCkfo4YGOMvdEjZ3ny",
"livemode": false,
"metadata": {
},
"pending_setup_intent": null,
"plan": {
"id": "plan_FYHrCVDopLPS37",
"object": "plan",
"active": true,
"aggregate_usage": null,
"amount": 2900,
"amount_decimal": "2900",
"billing_scheme": "per_unit",
"created": 1564792787,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {
},
"nickname": "Uproar Basic",
"product": "prod_FYHpmwiftJrqpC",
"tiers": null,
"tiers_mode": null,
"transform_usage": null,
"trial_period_days": null,
"usage_type": "licensed"
},
"quantity": 1,
"schedule": null,
"start": 1568957302,
"start_date": 1568957293,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
},
"previous_attributes": {
"cancel_at": null,
"cancel_at_period_end": false,
"canceled_at": null,
"start": 1568957293
}
}
I'm not sure code in config/initializers/stripe_events.rb can have access to app/controllers once your app is launched.
You should call a service :
config/initializers/stripe_events.rb
StripeEvent.configure do |events|
events.subscribe "customer.subscription.updated" do |event|
StripeUdpateSubscription.new
end
end
app/services/stripe_update_subscription.rb
class StripeUpdateSubscription
def call(event)
..// you code here
end
end

Current period end value saving as 0 instead of actual value

I am trying to save the Stripe's user current_period_end to the database. When I create a new subscription the value saves as 0 instead of the actual date their subscription ends.
Is there something I'm missing?
It should be saving as:
"current_period_end": 1441292360
Subscription.rb:
def save_with_stripe_payment
customer = Stripe::Customer.create(description: email, plan: plan_id, card: stripe_card_token)
self.stripe_customer_token = customer.id
self.cancellation_date = customer.subscriptions.first.current_period_end
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
It's possible that this could be an issue with the type of data you're receiving and how you're storing it in your database. Based on the information you have given I would expect you have the wrong field type.
Your code is correct so I would double check to see if your field is a integer.
When Strip creates a new customer it returns the object posted at the bottom of this question.
To access the current_period_end you would need to do customer.subscriptions.data.first["current_period_end"]
{
"object": "customer",
"created": 1409190039,
"id": "cus_4fdAW5ftNQow1a",
"livemode": false,
"description": "new_paying_customer",
"email": null,
"delinquent": false,
"metadata": {},
"subscriptions": {
"object": "list",
"total_count": 1,
"has_more": false,
"url": "/v1/customers/cus_4fdAW5ftNQow1a/subscriptions",
"data": [
{
"id": "sub_4fdAS9IlSOFfiv",
"plan": {
"interval": "month",
"name": "Basic Plan",
"created": 1409178429,
"amount": 1200,
"currency": "usd",
"id": "basic",
"object": "plan",
"livemode": false,
"interval_count": 1,
"trial_period_days": null,
"metadata": {},
"statement_description": null
},
"object": "subscription",
"start": 1409190039,
"status": "active",
"customer": "cus_4fdAW5ftNQow1a",
"cancel_at_period_end": false,
"current_period_start": 1409190039,
"current_period_end": 1411868439,
"ended_at": null,
"trial_start": null,
"trial_end": null,
"canceled_at": null,
"quantity": 1,
"application_fee_percent": null,
"discount": null,
"metadata": {}
}
]
},
"discount": null,
"account_balance": 0,
"currency": "usd",
"cards": {
"object": "list",
"total_count": 1,
"has_more": false,
"url": "/v1/customers/cus_4fdAW5ftNQow1a/cards",
"data": [
{
"id": "card_14WHtz4rPA98z9GRTW1QMenU",
"object": "card",
"last4": "4242",
"brand": "Visa",
"funding": "unknown",
"exp_month": 1,
"exp_year": 2015,
"fingerprint": "0qYXzA0d9EZtsgQ6",
"customer": "cus_4fdAW5ftNQow1a"
}
]
},
"default_card": "card_14WHtz4rPA98z9GRTW1QMenU"
}
This is just a shot in the dark (because I don't know the format of your cancellation_date field or the database you are using), but are you sure you are handling the returned timestamp correctly?
If cancellation_date is a DateTime field, I believe you have to do something like:
cpe = customer.subscriptions.first.current_period_end
self.cancellation_date = Time.at(cpe).to_datetime
If that isn't the problem then I'd use the console and/or the server output to make sure current_period_end is returning what you expect it to when you call Stripe::Customer.create (like others have suggested). You really need to determine when the "switch to 0" is happening, so I'd check (in this order):
The response from Stripe when you create the customer
The value of customer.subscriptions.first.current_period_end
The value of self.cancellation_date after assignment but before saving
There may also be validations or before_save filters that are messing with this field before hitting the database.
That's all my ideas for now :)
Hope this helps!

Resources