Необходимо обновить количество товаров до нуля после проверки полосы и попадания веб-перехватчика в рельсы 6 - PullRequest
1 голос
/ 28 мая 2020

Я создаю сайт для художников, чтобы продавать свои произведения искусства. Для платежей используется полосная касса. У меня настроены касса и веб-перехватчик, и мне нужно обновить количество товара до 0, как только веб-перехватчик сработает и сеанс проверки завершится. 1003 *

class CheckoutController < ApplicationController

  def create
    piece = Piece.find(params[:id])

    if piece.nil?
      redirect_to root_path
      return
    end 

    @session = Stripe::Checkout::Session.create(
      payment_method_types: [:card],
      line_items: [{
        name: piece.name,
        description: piece.description,
        amount: (piece.price*100).to_i,
        currency: 'usd',
        quantity: 1
      }],
      shipping_address_collection: {
        allowed_countries: ['US', 'CA'],
      },
      success_url: checkout_success_url,
      cancel_url: checkout_cancel_url
      )

    respond_to do |format|
      format.js
    end

  end 

  def success   

  end

  def cancel

  end


end

Вот контроллер событий веб-перехватчика

class WebhookEventsController < ApplicationController
  # ignore CSRF
  skip_before_action :verify_authenticity_token

  def create

    if !valid_signatures?
      render json: { message: "Invalid sigs"}, status: 400
      return
    end

    # idempotent
    if !WebhookEvent.find_by(source: params[:source], external_id: external_id).nil?
      render json: { message: "Already Processed #{ external_id }"}
      return
    end

    event = WebhookEvent.create(webhook_params)
    ProcessEventsJob.perform_later(event.id)    
    render json: params

  end

  def valid_signatures?
    if params[:source] == 'stripe'
      begin
        wh_secret = Rails.application.credentials.dig(:stripe, :wh)
        Stripe::Webhook.construct_event(
          request.body.read,
          request.env["HTTP_STRIPE_SIGNATURE" ],
          wh_secret
        )
      rescue Stripe::SignatureVerificationError => e
        return false
      end
    end
    true
  end

  def external_id
    return params[:id] if params[:source] == 'stripe'

    SecureRandom.hex
  end

  def webhook_params
    {
      source: params[:source],
      data: params.except(:source, :action, :controller).permit!,
      external_id: external_id
    }
  end
end

Вот обработчик полосы, где я считаю, что код для обновления количества штук должен go

module Events
  class StripeHandler
    def self.process(event)
      stripe_event = Stripe::Event.construct_from(event.data)

      case stripe_event.type
      when 'checkout.session.completed'
        checkout_session = stripe_event.data.object
        # now can do #{ checkout_session.customer }.. or some attribute of checkout_session object
        puts "*** Do things here i.e. logic for emails/inventory management"

      end
    end
  end
end

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

1 Ответ

0 голосов
/ 28 мая 2020

Здесь пара примечаний:

  1. Возможно, вы захотите установить client_reference_id на идентификатор объекта, что упрощает согласование: https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session -client_reference_id

  2. Вам нужно либо проверить line_items в завершенном сеансе, либо использовать client_reference_id, чтобы найти товар, купленный вашим клиентом после завершения сеанса.

Логин вашего контроллера c пока выглядит правильно. Вам понадобится поле quantity в Piece. Я предполагаю, что вы передаете {client_reference_id: piece.id} при создании CheckoutSession. С этим предположением ваш веб-перехватчик logi c выглядит следующим образом:

module Events
  class StripeHandler
    def self.process(event)
      stripe_event = Stripe::Event.construct_from(event.data)

      case stripe_event.type

      when 'checkout.session.completed'
        Piece.transaction do
          piece = Piece.find(id: checkout.client_reference_id)
          raise Exception.new("item already purchased!") if piece.quantity == 0
          piece.quantity = 0
          piece.save!
        end
      end
    end
  end
end

Это реализует простой сценарий «первый платит выигрывает», поэтому первый человек, который проходит через Checkout для данной части, платит, и чей веб-перехватчик checkout.session.completed будет отправлен вашему приложению и обработан первым, получит объект Piece. Если два человека платят одновременно, то получить Часть может только один, поэтому вы можете сделать что-то вроде автоматического возмещения покупателю и отправки им электронного письма.

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

...