Untitled

 avatar
unknown
ruby
a month ago
5.4 kB
5
Indexable
module BxBlockInapppurchasing
  class ProgramWebhooksController < ApplicationController
    skip_before_action :validate_json_web_token, :current_user, only: [:apple_iap, :google_iap]

    # Handle Apple IAP webhooks for programs
    def apple_iap
      signed_payload = params[:signedPayload]

      decoded_payload = decode_jwt(signed_payload)
      process_webhook_data(decoded_payload)
      
      render json: { message: 'Success' }, status: :ok
    rescue JWT::DecodeError => e
      render json: { error: "JWT error: #{e.message}" }, status: :unprocessable_entity
    end

    # Handle Google IAP webhooks for programs
    def google_iap
      signed_payload = params[:message][:data]

      decoded_payload = decode_base64(signed_payload)
      manage_google_program(decoded_payload)
      
      render json: { message: 'Success' }, status: :ok
    rescue JWT::DecodeError => e
      render json: { error: "JWT error: #{e.message}" }, status: :unprocessable_entity
    rescue JSON::ParserError => e
      render json: { error: "JSON parse error: #{e.message}" }, status: :unprocessable_entity
    end

    private

    # Decode JWT token from Apple
    def decode_jwt(signed_payload)
      JWT.decode(signed_payload, nil, false).first
    end

    # Process Apple webhook data
    def process_webhook_data(decoded_token)
      transaction_info = decoded_token.dig('data', 'signedTransactionInfo')
      webhook_response = JWT.decode(transaction_info, nil, false).first

      manage_program(webhook_response) if webhook_response
    end

    # Process Apple program purchase
    def manage_program(transaction)
      program = find_program_by_apple_id(transaction['productId'])
      user = get_user_from_transaction(transaction)
      
      return unless program && user

      ActiveRecord::Base.transaction do
        program_purchase = create_program_purchase(user, program)
        if program_purchase
          create_program_subscriptions(user, program)
          update_program_payment_history(transaction, user, program_purchase)
        end
      end
    end

    # Find program by Apple product ID
    def find_program_by_apple_id(product_id)
      BxBlockCustomUserSubs::Program.find_by(apple_product_id: product_id)
    end

    # Find program by Google product ID
    def find_program_by_google_id(product_id)
      BxBlockCustomUserSubs::Program.find_by(google_product_id: product_id)
    end

    # Create program purchase record
    def create_program_purchase(user, program)
      BxBlockCustomUserSubs::ProgramPurchase.create(
        account_id: user.id,
        program_id: program.id,
        is_expire: false,
        user_type: 'normal_user',
        active: true
      )
    end

    # Create subscription records for each subscription in the program
    def create_program_subscriptions(user, program)
      program.subscriptions.each do |subscription|
        BxBlockCustomUserSubs::UserSubscription.create(
          account_id: user.id,
          subscription_id: subscription.id,
          is_expire: false,
          user_type: 'normal_user',
          active: true
        )
      end
    end

    # Get user from transaction data
    def get_user_from_transaction(transaction)
      AccountBlock::Account.find_by(uuid: transaction['appAccountToken'])
    end

    # Update payment history for program purchase
    def update_program_payment_history(transaction, user, program_purchase)
      currency = transaction['currency'] || 'USD'
      BxBlockStripeIntegration::PaymentHistory.create!(
        account_id: user.id,
        program_id: program_purchase.id,
        payment_type: 'program',
        amount: program_purchase.program&.price,
        currency: currency,
        status: 'success',
        stripe_payment_intent_id: transaction['transactionId'] || @response['latestOrderId'],
        payment_method: 'in_app_purchase',
        customer_id: 'sk'
      )
    end

    # Decode Base64 data from Google
    def decode_base64(signed_payload)
      decoded_data = Base64.decode64(signed_payload)
      JSON.parse(decoded_data)
    end

    # Process Google program purchase
    def manage_google_program(transaction)
      notification = transaction['subscriptionNotification']
      return unless valid_google_transaction?(notification)

      user = get_google_user(transaction)
      program = find_program_by_google_id(notification['subscriptionId'])
      
      return unless user && program

      ActiveRecord::Base.transaction do
        program_purchase = create_program_purchase(user, program)
        if program_purchase
          create_program_subscriptions(user, program)
          update_program_payment_history(notification, user, program_purchase)
        end
      end
    end

    # Get user from Google transaction
    def get_google_user(transaction)
      @response = BxBlockStripeIntegration::GoogleApiService.new(
        transaction['packageName'], 
        transaction['subscriptionNotification']['purchaseToken']
      ).get_token unless Rails.env.test?
      
      return nil if @response.nil? || @response[:error]
      uuid = @response['externalAccountIdentifiers']['obfuscatedExternalAccountId']

      AccountBlock::Account.find_by(uuid: uuid)
    end

    # Validate Google transaction
    def valid_google_transaction?(transaction)
      transaction['purchaseToken'].present? && transaction['notificationType'] == 4
    end
  end
end
Editor is loading...
Leave a Comment