rails 4 个应用的 Stripe 优惠券未反映在费用中或保存在数据库中
Stripe coupon not reflected in charge or saved in database for rails 4 app
我们已经让 Stripe 在我们的 rails 4 应用程序中使用 Mastering Modern Payments 方法进行订阅支付。我们现在正在尝试添加优惠券。我们想使用 Stripe 来管理优惠券(在 Stripe 仪表板中创建优惠券)。
问题是当用户付款时,优惠券并没有减少收取的金额,也没有与用户和订阅信息一起保存到应用程序数据库中。我们没有收到任何错误。
工作原理:我们在用户支付时在哈希中看到优惠券代码,优惠券是在 Stripe 中设置的。总体而言,用户可以注册并支付罚款。我们在 Devise 中执行两步创建用户,然后让他们付款。当他们支付订阅费用时,我们的应用程序就会激活。
我们知道这里缺少优惠券的一部分,但我们正在努力弄清楚那是什么以及应该如何实施?我在 rails 中读到有关创建虚拟属性的信息,所以也许我们可以为优惠券这样做,因为目前在用户 table.
中没有任何优惠券信息
当用户注册订阅时,输出如下所示(实际数据已替换为发布):
... Started POST "/subscriptions" for 127.0.0.1 at 2015-11-30 10:33:40 -0800
Processing by SubscriptionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XYZ", "plan_id"=>"5", "email_address"=>"test55@gmail.com", "coupon"=>"123", "stripeToken"=>"tok_xyz"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT 1 [["id", 52]]
Plan Load (0.3ms) SELECT "plans".* FROM "plans" WHERE "plans"."id" = LIMIT 1 [["id", 5]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."email" = LIMIT 1 [["email", "test55@gmail.com"]]
(0.3ms) BEGIN
SQL (0.4ms) UPDATE "users" SET "stripe_customer_id" = , "updated_at" = WHERE "users"."id" = [["stripe_customer_id", "cus_7Rq9Kv4nGh6uD2"], ["updated_at", "2015-11-30 18:33:41.930863"], ["id", 52]]
SQL (48.6ms) INSERT INTO "subscriptions" ("plan_id", "user_id", "created_at", "updated_at") VALUES (, , , ) RETURNING "id" [["plan_id", 5], ["user_id", 52], ["created_at", "2015-11-30 18:33:41.934364"], ["updated_at", "2015-11-30 18:33:41.934364"]]
DEPRECATION WARNING: `serialized_attributes` is deprecated without replacement, and will be removed in Rails 5.0. (called from serialized_attributes at /usr/local/rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/attribute_methods/serialization.rb:56)...
用户和订阅的架构(优惠券是订阅中的一列 table):
schema.rb:
...
create_table "subscriptions", force: :cascade do |t|
t.date "purchase_date"
t.boolean "active"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "plan_id"
t.string "stripe_id"
t.string "coupon"
end
add_index "subscriptions", ["plan_id"], name: "index_subscriptions_on_plan_id", using: :btree
add_index "subscriptions", ["user_id"], name: "index_subscriptions_on_user_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: ""
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "role"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.integer "invited_by_id"
t.string "invited_by_type"
t.integer "invitations_count", default: 0
t.boolean "terms_accepted", default: false
t.string "phone_number"
t.string "plan_id"
t.string "employer"
t.string "stripe_customer_id"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count", using: :btree
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
...
优惠券在创建订阅服务对象中:
create_subscription.rb
class CreateSubscription
def self.call(plan, email_address, token)
user, raw_token = CreateUser.call(email_address)
subscription = Subscription.new(
plan: plan,
user: user
)
begin
stripe_sub = nil
if user.stripe_customer_id.blank?
customer = Stripe::Customer.create(
source: token,
email: user.email,
plan: plan.stripe_id,
coupon: subscription.coupon,
)
user.stripe_customer_id = customer.id
user.save!
stripe_sub = customer.subscriptions.first
else
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
stripe_sub = customer.subscriptions.create(
plan: plan.stripe_id
)
end
subscription.stripe_id = stripe_sub.id
subscription.save!
rescue Stripe::StripeError => e
subscription.errors[:base] << e.message
end
subscription
end
end
优惠券在支付页面:
app/views/subscriptions/new.html.haml
= content_for :header do
%script{src: 'https://js.stripe.com/v2/', type: 'text/javascript'}
:javascript
$(function(){
Stripe.setPublishableKey("#{Rails.configuration.stripe[:publishable_key]}");
});
%script{src: '/subscriptions.js', type: 'text/javascript'}
- unless @subscription.errors.blank?
= @subscription.errors.full_messages.to_sentence
%h2
Subscribing to #{@plan.name}
= form_for @subscription, html: { id: 'payment-form' } do |f|
%input{name: 'plan_id', type: 'hidden', value: @plan.id}/
%span.payment-errors
.form-row
%label
%span Email Address
%input{name: 'email_address', size: '20', type: 'email', value: @user.email}
.form-row
%label
%span Card Number
%input{size: '20', type: 'text', data: {stripe: 'number'}}
.form-row
%label
%span CVC
%input{size: '4', type: 'text', data: {stripe: 'cvc'}}
.form-row
%label
%span Expiration (MM/YYYY)
%input{size: '2', type: 'text', data: {stripe: 'exp-month'}}
%span /
%input{size: '4', type: 'text', data: {stripe: 'exp-year'}}
.form-row
%label
%span Promo code, if any
%input{name: 'coupon', size: '20', type: 'text', value: @coupon}
%button{type: 'submit', class: 'btn btn-lg btn-primary'} Pay Now
我们的订阅模式是这样的:
subscription.rb:
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :plan
has_paper_trail
def inactive?
active ? false : true
end
def active?
active
end
end
我们如何在费用中反映 Stripe 优惠券并将其保存在我们的应用程序数据库中?谢谢。
您的 CreateSubscription
服务不提供传递优惠券代码的途径。
您需要为此添加一个新参数,例如。
class CreateSubscription
def self.call(plan, email_address, token, coupon = nil)
# ...
subscription = Subscription.new(
plan: plan,
user: user,
coupon: coupon
)
# ...
end
end
此外,对于您提供的代码,还有一些其他事项需要注意:
customer = Stripe::Customer.create(
source: token,
email: user.email,
plan: plan.stripe_id,
coupon: subscription.coupon
)
Stipe 允许您对客户和订阅设置 coupon
。计费时,应用于订阅的折扣会覆盖在客户范围内应用的折扣。参见 https://stripe.com/docs/api#subscription_object
因此,如果您的客户取消订阅,或有其他(多个)订阅。根据您的优惠券设置,他们也可能会获得折扣。
因此,根据您希望发生的情况,您可能只想将优惠券传递给 Stripe::Subscription
而不是传递给 Stripe::Customer
。
我们已经让 Stripe 在我们的 rails 4 应用程序中使用 Mastering Modern Payments 方法进行订阅支付。我们现在正在尝试添加优惠券。我们想使用 Stripe 来管理优惠券(在 Stripe 仪表板中创建优惠券)。
问题是当用户付款时,优惠券并没有减少收取的金额,也没有与用户和订阅信息一起保存到应用程序数据库中。我们没有收到任何错误。
工作原理:我们在用户支付时在哈希中看到优惠券代码,优惠券是在 Stripe 中设置的。总体而言,用户可以注册并支付罚款。我们在 Devise 中执行两步创建用户,然后让他们付款。当他们支付订阅费用时,我们的应用程序就会激活。
我们知道这里缺少优惠券的一部分,但我们正在努力弄清楚那是什么以及应该如何实施?我在 rails 中读到有关创建虚拟属性的信息,所以也许我们可以为优惠券这样做,因为目前在用户 table.
中没有任何优惠券信息当用户注册订阅时,输出如下所示(实际数据已替换为发布):
... Started POST "/subscriptions" for 127.0.0.1 at 2015-11-30 10:33:40 -0800
Processing by SubscriptionsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"XYZ", "plan_id"=>"5", "email_address"=>"test55@gmail.com", "coupon"=>"123", "stripeToken"=>"tok_xyz"}
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = ORDER BY "users"."id" ASC LIMIT 1 [["id", 52]]
Plan Load (0.3ms) SELECT "plans".* FROM "plans" WHERE "plans"."id" = LIMIT 1 [["id", 5]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."email" = LIMIT 1 [["email", "test55@gmail.com"]]
(0.3ms) BEGIN
SQL (0.4ms) UPDATE "users" SET "stripe_customer_id" = , "updated_at" = WHERE "users"."id" = [["stripe_customer_id", "cus_7Rq9Kv4nGh6uD2"], ["updated_at", "2015-11-30 18:33:41.930863"], ["id", 52]]
SQL (48.6ms) INSERT INTO "subscriptions" ("plan_id", "user_id", "created_at", "updated_at") VALUES (, , , ) RETURNING "id" [["plan_id", 5], ["user_id", 52], ["created_at", "2015-11-30 18:33:41.934364"], ["updated_at", "2015-11-30 18:33:41.934364"]]
DEPRECATION WARNING: `serialized_attributes` is deprecated without replacement, and will be removed in Rails 5.0. (called from serialized_attributes at /usr/local/rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/attribute_methods/serialization.rb:56)...
用户和订阅的架构(优惠券是订阅中的一列 table):
schema.rb:
...
create_table "subscriptions", force: :cascade do |t|
t.date "purchase_date"
t.boolean "active"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.integer "plan_id"
t.string "stripe_id"
t.string "coupon"
end
add_index "subscriptions", ["plan_id"], name: "index_subscriptions_on_plan_id", using: :btree
add_index "subscriptions", ["user_id"], name: "index_subscriptions_on_user_id", using: :btree
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: ""
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at"
t.datetime "updated_at"
t.string "name"
t.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.integer "role"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.integer "invited_by_id"
t.string "invited_by_type"
t.integer "invitations_count", default: 0
t.boolean "terms_accepted", default: false
t.string "phone_number"
t.string "plan_id"
t.string "employer"
t.string "stripe_customer_id"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count", using: :btree
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id", using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
...
优惠券在创建订阅服务对象中:
create_subscription.rb
class CreateSubscription
def self.call(plan, email_address, token)
user, raw_token = CreateUser.call(email_address)
subscription = Subscription.new(
plan: plan,
user: user
)
begin
stripe_sub = nil
if user.stripe_customer_id.blank?
customer = Stripe::Customer.create(
source: token,
email: user.email,
plan: plan.stripe_id,
coupon: subscription.coupon,
)
user.stripe_customer_id = customer.id
user.save!
stripe_sub = customer.subscriptions.first
else
customer = Stripe::Customer.retrieve(user.stripe_customer_id)
stripe_sub = customer.subscriptions.create(
plan: plan.stripe_id
)
end
subscription.stripe_id = stripe_sub.id
subscription.save!
rescue Stripe::StripeError => e
subscription.errors[:base] << e.message
end
subscription
end
end
优惠券在支付页面:
app/views/subscriptions/new.html.haml
= content_for :header do
%script{src: 'https://js.stripe.com/v2/', type: 'text/javascript'}
:javascript
$(function(){
Stripe.setPublishableKey("#{Rails.configuration.stripe[:publishable_key]}");
});
%script{src: '/subscriptions.js', type: 'text/javascript'}
- unless @subscription.errors.blank?
= @subscription.errors.full_messages.to_sentence
%h2
Subscribing to #{@plan.name}
= form_for @subscription, html: { id: 'payment-form' } do |f|
%input{name: 'plan_id', type: 'hidden', value: @plan.id}/
%span.payment-errors
.form-row
%label
%span Email Address
%input{name: 'email_address', size: '20', type: 'email', value: @user.email}
.form-row
%label
%span Card Number
%input{size: '20', type: 'text', data: {stripe: 'number'}}
.form-row
%label
%span CVC
%input{size: '4', type: 'text', data: {stripe: 'cvc'}}
.form-row
%label
%span Expiration (MM/YYYY)
%input{size: '2', type: 'text', data: {stripe: 'exp-month'}}
%span /
%input{size: '4', type: 'text', data: {stripe: 'exp-year'}}
.form-row
%label
%span Promo code, if any
%input{name: 'coupon', size: '20', type: 'text', value: @coupon}
%button{type: 'submit', class: 'btn btn-lg btn-primary'} Pay Now
我们的订阅模式是这样的:
subscription.rb:
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :plan
has_paper_trail
def inactive?
active ? false : true
end
def active?
active
end
end
我们如何在费用中反映 Stripe 优惠券并将其保存在我们的应用程序数据库中?谢谢。
您的 CreateSubscription
服务不提供传递优惠券代码的途径。
您需要为此添加一个新参数,例如。
class CreateSubscription
def self.call(plan, email_address, token, coupon = nil)
# ...
subscription = Subscription.new(
plan: plan,
user: user,
coupon: coupon
)
# ...
end
end
此外,对于您提供的代码,还有一些其他事项需要注意:
customer = Stripe::Customer.create(
source: token,
email: user.email,
plan: plan.stripe_id,
coupon: subscription.coupon
)
Stipe 允许您对客户和订阅设置 coupon
。计费时,应用于订阅的折扣会覆盖在客户范围内应用的折扣。参见 https://stripe.com/docs/api#subscription_object
因此,如果您的客户取消订阅,或有其他(多个)订阅。根据您的优惠券设置,他们也可能会获得折扣。
因此,根据您希望发生的情况,您可能只想将优惠券传递给 Stripe::Subscription
而不是传递给 Stripe::Customer
。