Как обновить таблицу подписки и продаж после получения чеков с полосками через Payola? - PullRequest
0 голосов
/ 17 января 2019

Я могу получать ответы веб-хуков от Stripe через блоки методов Payola StripeEvent. Каждый ответ отображает заголовок HTTP «200 OK», когда я нажимаю кнопку «Проверить веб-зацепки» на панели инструментов Stripe. Проблема, с которой я столкнулся, заключается в том, что Payola :: StripeWebhook хранятся в базе данных, но таблица подписки и продаж не обновляется. В результате пользователи остаются на пробной версии, и я не могу регистрировать платежи, потому что их записи находятся в тупике. Мне сказали, что пропуск этих событий из-за отключений сервера / аппаратного сбоя может привести к неправильному обновлению записей. Я также вижу, что существует метод с именем Payola :: Subscription # sync_with! , который должен синхронизировать и обновлять записи. Как я могу исправить свои StripeEvents, чтобы изменить данные модели подписки / продажи с помощью Stripe Web Hook Responses?

Я создавал события для каждого ответа веб-ловушки, который, по моему мнению, был необходим. Например, я сделал событие webhook для charge.refunded, invoice.payment_failed, invoice.payment_succeeded, customer.subscription.deleted и trial_will_end. Я вижу ответ на моем сервере от Stripe, но не вижу обновлений для таблиц.

Журнал сервера

Started POST "/payola/events" for 54.187.205.235 at 2019-01-16 19:54:07 -0500
Processing by StripeEvent::WebhookController#event as XML
Parameters: {"id"=>"evt_1DtP922xuZZdQdXfrVD0Iel0", "object"=>"event", "api_version"=>"2017-06-05", "created"=>1547686448, "data"=>{"object"=>{"id"=>"biz_basic_account", "object"=>"plan", "active"=>true, "aggregate_usage"=>nil, "amount"=>4600, "billing_scheme"=>"per_unit", "created"=>1543343985, "currency"=>"usd", "interval"=>"month", "interval_count"=>1, "livemode"=>false, "metadata"=>{}, "name"=>"Business Basics | $4.00", "nickname"=>"Business Basic", "product"=>"prod_E3I35OUSByBfci", "statement_descriptor"=>nil, "tiers"=>nil, "tiers_mode"=>nil, "transform_usage"=>nil, "trial_period_days"=>3, "usage_type"=>"licensed"}, "previous_attributes"=>{"nickname"=>nil, "trial_period_days"=>nil}}, "livemode"=>false, "pending_webhooks"=>1, "request"=>{"id"=>"req_E9ztRRhsBJ1PyU", "idempotency_key"=>nil}, "type"=>"plan.updated", "webhook"=>{"id"=>"evt_1DtP922xuZZdQdXfrVD0Iel0", "object"=>"event", "api_version"=>"2017-06-05", "created"=>1547686448, "data"=>{"object"=>{"id"=>"biz_basic_account", "object"=>"plan", "active"=>true, "aggregate_usage"=>nil, "amount"=>4600, "billing_scheme"=>"per_unit", "created"=>1543343985, "currency"=>"usd", "interval"=>"month", "interval_count"=>1, "livemode"=>false, "metadata"=>{}, "name"=>"Business Basics | $4.00", "nickname"=>"Business Basic", "product"=>"prod_E3I35OUSByBfci", "statement_descriptor"=>nil, "tiers"=>nil, "tiers_mode"=>nil, "transform_usage"=>nil, "trial_period_days"=>3, "usage_type"=>"licensed"}, "previous_attributes"=>{"nickname"=>nil, "trial_period_days"=>nil}}, "livemode"=>false, "pending_webhooks"=>1, "request"=>{"id"=>"req_E9ztRRhsBJ1PyU", "idempotency_key"=>nil}, "type"=>"plan.updated"}}
 Payola::StripeWebhook Exists (1.0ms)  SELECT  1 AS one FROM "payola_stripe_webhooks" WHERE "payola_stripe_webhooks"."stripe_id" = $1 LIMIT $2  [["stripe_id", "evt_1DtPegrgr922xuZZdQdXfrrgegeD0rgegl0"], ["LIMIT", 1]]
   (0.0ms)  BEGIN
  CACHE Payola::StripeWebhook Exists (0.0ms)  SELECT  1 AS one FROM "payola_stripe_webhooks" WHERE "payola_stripe_webhooks"."stripe_id" = $1 LIMIT $2  [["stripe_id", "evt_1DtPegrgr922xuZZdQdXfrrgegeD0rgegl0"], ["LIMIT", 1]]
  Payola::StripeWebhook Create (0.0ms)  INSERT INTO "payola_stripe_webhooks" ("stripe_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id"  [["stripe_id", "evt_1DtPegrgr922xuZZdQdXfrrgegeD0rgegl0"], ["created_at", "2019-01-17 00:54:08.269998"], ["updated_at", "2019-01-17 00:54:08.269998"]]
   (0.0ms)  COMMIT
Completed 200 OK in 469ms (ActiveRecord: 1.0ms)

payola.rb / Управление StripeEvent

Payola.configure do |config|
  # Example subscription:
  #
  # config.subscribe 'payola.package.sale.finished' do |sale|
  #   EmailSender.send_an_email(sale.email)
  # end
  #
  # In addition to any event that Stripe sends, you can subscribe
  # to the following special payola events:
  #
  #  - payola.<sellable class>.sale.finished
  #  - payola.<sellable class>.sale.refunded
  #  - payola.<sellable class>.sale.failed
  #
  # These events consume a Payola::Sale, not a Stripe::Event
  #
  # Example charge verifier:
  #
  # config.charge_verifier = lambda do |sale|
  #   raise "Nope!" if sale.email.includes?('yahoo.com')
  # end

  config.secret_key = ENV['STRIPE_SECRET_KEY']
  config.publishable_key = ENV['STRIPE_PUBLISHABLE_KEY']

  config.charge_verifier = lambda do |event|
    user = User.find_by(email: event.email)
      if event.is_a?(Payola::Subscription) && user.subscriptions.active.any?
    raise 'Error: This user already has a subscription'
   end

      event.owner = user
      event.save!
   end

  # Keep this subscription unless you want to disable refund handling
  config.subscribe 'charge.refunded' do |event|
    subscription = Payola::Subscription.find_by(stripe_id: event.data.object.id)
    subscription.refund! unless sale.refunded?
  end

  Payola.subscribe 'invoice.payment_failed' do |event|
    subscription = Payola::Subscription.find_by(stripe_id: event.data.object.id)
    user = User.find_by(email: subscription.email)
    ChargeFailedMailer.charge_failure_user(user)
    user.update_attribute(:account_delinquent, true)
  end

  Payola.subscribe 'invoice.payment_succeeded' do |event|
    subscription = Payola::Subscription.find_by(stripe_id: event.data.object.id)
      user = User.find_by(email: subscription.email)
      sale = Sale.find_by(stripe_id: event.data.object.id)
      ChargeSucceededMailer.charge_succeeded_user(user)
      user.update_attribute(:account_delinquent, false)
      subscription.update_attribute(:status, event.data.object.status)
      subscription.save
  end

  Payola.subscribe 'customer.subscription.deleted' do |event|
    subscription = Payola::Subscription.find_by(stripe_id: event.data.object.id)
      user = User.find_by(email: subscription.email)
      sale = Sale.find_by(stripe_id: event.data.object.id)
    CanceledSubscriptionMailer.subscription_canceled_for_user(user).deliver
  user.destroy

  end

  Payola.subscribe 'customer.subscription.trial_will_end' do |event|
    subscription = Payola::Subscription.find_by(stripe_id: event.data.object.id)
      user = User.find_by(email: subscription.email)
      sale = Sale.find_by(stripe_id: event.data.object.id)
      TrialEndingMailer.trial_ending_for_user(user)

  end

  Payola.subscribe 'customer.subscription.updated' do |event|
    puts 'Subscription updated!'
  end
end

маршруты

Rails.application.routes.draw do
  match '/subscription_expired', to: 'service_disruption#index', :via => :get
  #mount Payola::Engine => '/payola', as: :payola
  mount ActionCable.server => '/cable'
  mount CountryStateSelect::Rails::Engine => '/'
  get 'my_review/index'
  require 'sidekiq/web'
  mount Sidekiq::Web => '/sidekiq'
  post '/rate' => 'rater#create', :as => 'rate'
  get 'update_account/index'
  get 'u_help', to: 'user_help#index', as: :user_help
  get 'username_validator/:username', to: 'usernames#username_validator'

  devise_for :users, path: '', path_names: {sign_in: 'login', sign_out: 'logout', sign_up: 'signup'}, controllers: {registrations: 'users/registrations'}

  namespace :api do
    scope :v1 do
    end
  end

  devise_scope :user do
    put 'user_change_plan', to: 'users/registrations#user_change_plan'
    put 'user_change_credit_card', to: 'users/registrations#user_change_credit_card'
    authenticated do
      root to: 'user_dashboard#index', as: 'authenticated_user_root'
    end
    unauthenticated do
      root to: 'home#index', as: 'unauthenticated_user_root'
    end
  end

  controller :home do
    get :index, to: 'home#index', as: 'home', path: 'home'
    get :pricing, to: 'home#pricing', as: 'pricing', path: 'pricing'
    get :about, to: 'home#about', as: 'about', path: 'about'
    get :contact, to: 'home#contact', as: 'contact', path: 'contact'
    get :login_portal, to: 'home#login_portal', as: 'login_portal', path: 'login_portal'
    get :signup_portal, to: 'home#signup_portal', as: 'signup_portal', path: 'signup_portal'
  end


  scope module: 'payola' do
    mount StripeEvent::Engine => 'payola/events', as: :payola
    post 'payola/buy/:product_class/:permalink' => 'transactions#create', as: :buy
    get 'payola/confirm/:guid' => 'transactions#show', as: :confirm
    get 'payola/status/:guid' => 'transactions#status', as: :status
    post 'payola/subscribe/:plan_class/:plan_id' => 'subscriptions#create', as: :subscribe
    get 'payola/confirm_subscription/:guid' => 'subscriptions#show', as: :confirm_subscription
    get 'payola/subscription_status/:guid' => 'subscriptions#status', as: :subscription_status
    delete 'payola/cancel_subscription/:guid' => 'subscriptions#destroy', as: :cancel_subscription
    post 'payola/change_plan/:guid' => 'subscriptions#change_plan', as: :change_subscription_plan
    post 'payola/change_quantity/:guid' => 'subscriptions#change_quantity', as: :change_subscription_quantity
    post 'payola/update_card/:guid' => 'subscriptions#update_card', as: :update_card
    post 'payola/update_customer/:id' => 'customers#update', as: :update_customer
    post 'payola/create_card/:customer_id' => 'cards#create', as: :create_card
    delete 'payola/destroy_card/:id/:customer_id' => 'cards#destroy', as: :destroy_card
  end

  root 'home#index'
end

application.js

//= require jquery3
......
//= require payola/subscription_form_onestep
//= require payola/subscription_form_twostep
//= require payola/checkout_button
//= require payola/form
//= require payola/subscription_checkout_button
//= require payola/subscription_form_register

stripe.rb

Rails.configuration.stripe = {
    :publishable_key => ENV['STRIPE_PUBLISHABLE_KEY'],
    :secret_key      => ENV['STRIPE_SECRET_KEY']
}

Stripe.api_key = Rails.application.secrets.stripe_api_key
StripeEvent.signing_secret = ENV['STRIPE_SIGNING_SECRET']

UPDATE изменив полосу события, пройдите по направлению к тому, что показывает драгоценный камень, и поместите его внизу. Я получаю ответ от webhook, как показано ниже.

Completed 200 OK in 260332ms (Views: 259165.4ms | ActiveRecord: 81.9ms)


Started POST "/events" for 54.187.174.169 at 2019-01-18 21:11:30 -0500
Processing by StripeEvent::WebhookController#event as XML
  Parameters: {"created"=>1326853478, "livemode"=>false, "id"=>"invoice.payment_00000000000000", "type"=>"invoice.payment_succeeded", "object"=>"event", "request"=>nil, "pending_webhooks"=>1, "api_version"=>"2017-06-05", "data"=>{"object"=>{"id"=>"in_00000000000000", "object"=>"invoice", "amount_due"=>900, "amount_paid"=>900, "amount_remaining"=>0, "application_fee"=>nil, "attempt_count"=>1, "attempted"=>true, "auto_advance"=>false, "billing"=>"charge_automatically", "billing_reason"=>"subscription", "charge"=>"_00000000000000", "closed"=>true, "currency"=>"usd", "custom_fields"=>nil, "customer"=>"cus_00000000000000", "date"=>1455648779, "default_source"=>nil, "description"=>nil, "discount"=>nil, "due_date"=>nil, "ending_balance"=>0, "finalized_at"=>1455648779, "footer"=>nil, "forgiven"=>false, "hosted_invoice_url"=>"https://pay.stripe.com/invoice/invst_1cWFwm2egegegegege", "invoice_pdf"=>"https://pay.stripe.com/invoice/invst_1cWFwm20xegegegegege/pdf", "lines"=>{"data"=>[{"id"=>"sub_00000000000000", "object"=>"line_item", "amount"=>900, "currency"=>"usd", "description"=>nil, "discountable"=>true, "livemode"=>false, "metadata"=>{}, "period"=>{"end"=>1502909579, "start"=>1500231179}, "plan"=>{"id"=>"gbsubscriptionlevel1_00000000000000", "object"=>"plan", "active"=>true, "aggregate_usage"=>nil, "amount"=>900, "billing_scheme"=>"per_unit", "created"=>1455057017, "currency"=>"usd", "interval"=>"month", "interval_count"=>1, "livemode"=>false, "metadata"=>{}, "name"=>"Going Big Subscription Basic", "nickname"=>nil, "product"=>"prod_00000000000000", "statement_descriptor"=>"Going Big SUBSCRIPTION", "tiers"=>nil, "tiers_mode"=>nil, "transform_usage"=>nil, "trial_period_days"=>nil, "usage_type"=>"licensed"}, "proration"=>false, "quantity"=>1, "subscription"=>nil, "subscription_item"=>"si_00000000000000", "type"=>"subscription"}], "has_more"=>false, "object"=>"list", "url"=>"/v1/invoices/in_17fDwV2xuZZdQdXgegegegeNB8uL/lines"}, "livemode"=>false, "metadata"=>{}, "next_payment_attempt"=>nil, "number"=>nil, "paid"=>true, "period_end"=>1455648779, "period_start"=>1455648779, "receipt_number"=>nil, "starting_balance"=>0, "statement_descriptor"=>nil, "status"=>"paid", "subscription"=>"sub_00000000000000", "subtotal"=>900, "tax"=>nil, "tax_percent"=>nil, "total"=>900, "webhooks_delivered_at"=>1455648780}}, "webhook"=>{"created"=>1326853478, "livemode"=>false, "id"=>"invoice.payment_00000000000000", "type"=>"invoice.payment_succeeded", "object"=>"event", "request"=>nil, "pending_webhooks"=>1, "api_version"=>"2017-06-05", "data"=>{"object"=>{"id"=>"in_00000000000000", "object"=>"invoice", "amount_due"=>900, "amount_paid"=>900, "amount_remaining"=>0, "application_fee"=>nil, "attempt_count"=>1, "attempted"=>true, "auto_advance"=>false, "billing"=>"charge_automatically", "billing_reason"=>"subscription", "charge"=>"_00000000000000", "closed"=>true, "currency"=>"usd", "custom_fields"=>nil, "customer"=>"cus_00000000000000", "date"=>1455648779, "default_source"=>nil, "description"=>nil, "discount"=>nil, "due_date"=>nil, "ending_balance"=>0, "finalized_at"=>1455648779, "footer"=>nil, "forgiven"=>false, "hosted_invoice_url"=>"https://pay.stripe.com/invoice/invst_1cWFwm2rggegegegeg", "invoice_pdf"=>"https://pay.stripe.com/invoice/invst_1cWrgegegegegege/pdf", "lines"=>{"data"=>[{"id"=>"sub_00000000000000", "object"=>"line_item", "amount"=>900, "currency"=>"usd", "description"=>nil, "discountable"=>true, "livemode"=>false, "metadata"=>{}, "period"=>{"end"=>1502909579, "start"=>1500231179}, "plan"=>{"id"=>"gbsubscriptionlevel1_00000000000000", "object"=>"plan", "active"=>true, "aggregate_usage"=>nil, "amount"=>900, "billing_scheme"=>"per_unit", "created"=>1455057017, "currency"=>"usd", "interval"=>"month", "interval_count"=>1, "livemode"=>false, "metadata"=>{}, "name"=>"Going Big Subscription Basic", "nickname"=>nil, "product"=>"prod_00000000000000", "statement_descriptor"=>"Going Big SUBSCRIPTION", "tiers"=>nil, "tiers_mode"=>nil, "transform_usage"=>nil, "trial_period_days"=>nil, "usage_type"=>"licensed"}, "proration"=>false, "quantity"=>1, "subscription"=>nil, "subscription_item"=>"si_00000000000000", "type"=>"subscription"}], "has_more"=>false, "object"=>"list", "url"=>"/v1/invoices/in_17fDwV2xuZZdQdegergegeg8uL/lines"}, "livemode"=>false, "metadata"=>{}, "next_payment_attempt"=>nil, "number"=>nil, "paid"=>true, "period_end"=>1455648779, "period_start"=>1455648779, "receipt_number"=>nil, "starting_balance"=>0, "statement_descriptor"=>nil, "status"=>"paid", "subscription"=>"sub_00000000000000", "subtotal"=>900, "tax"=>nil, "tax_percent"=>nil, "total"=>900, "webhooks_delivered_at"=>1455648780}}}}
  Payola::StripeWebhook Exists (109.9ms)  SELECT  1 AS one FROM "payola_stripe_webhooks" WHERE "payola_stripe_webhooks"."stripe_id" = $1 LIMIT $2  [["stripe_id", "invoice.payment_00000000000000"], ["LIMIT", 1]]
Completed 200 OK in 379ms (ActiveRecord: 114.9ms)

ОБНОВЛЕНИЕ 2

Я считаю, что это работает сейчас. Я получил событие ниже для одного из планов подписки.

Event Details
ID
evt_1Dv7l02xuZZdQdXfaSXmAOSz
Date
2019/01/21 18:44:26
Type
customer.subscription.updated
Source
Automatic

1 Ответ

0 голосов
/ 17 января 2019

Не совсем понятно, в чем проблема.Итак, вот несколько вариантов, чтобы рассмотреть возможность попробовать, если вы еще не пробовали их:

  • Проверьте Payola mount ed в config/routes.rb.Он должен выглядеть следующим образом:

    mount Payola::Engine => '/payments', as: :payments

  • Проверьте, выполняются ли фоновые задания, и просмотрите очереди заданий, чтобы увидеть, не поставлены ли какие-либо задания, связанные с payola, в очередь.

  • Убедитесь, что payola.rb находится в config/initializers/

  • Полностью перезапустите приложение и Spring в любое время, когда вы измените config/initializers/payola.rb, запустив bin/spring stop; bin/rails server

  • Проверьте любую конфигурацию StripeEvent во всем приложении на наличие неожиданностей.Аналогично для любой конфигурации Payola.

  • Обновите вызовы Payola.subscribe до config.subscribe в файле payola.rb, указанном выше.

  • Только в вашей среде разработки, отладкадрагоценный камень Payola, добавив свой собственный код в источник драгоценного камня Payola в любой точке интереса.Найдите его местоположение, запустив bundle show payola-payments, а затем откройте каталог, напечатанный в вашем редакторе кода.Вы можете внести изменения в любой из файлов в гем, чтобы помочь отладке.Каждый раз, когда вы вносите изменения в этот драгоценный камень, вам нужно будет сделать полный перезапуск, чтобы получить последние изменения: bin/spring stop; bin/rails server.Как только вы закончите отладку, верните гем в его первоначальное состояние без изменений, запустив bundle exec gem pristine payola-payments.

...