require_dependency "app_manager/application_controller" module AppManager class ChargesController < ApplicationController include HTTParty skip_before_action :verify_authenticity_token, :only => [:process_plan,:activate_global,:cancel_charge,:cancel_global] before_action :params_permit require 'time' require 'rack' def process_plan if params[:shop].present? && params[:plan_id].present? @shop = shop_data grandfathered_field = @field_names['grandfathered'] if !@shop.nil? plan_obj = AppManager::Client.new plan_data = plan_obj.get_plan(params[:plan_id], params[:shop]) # render json: plan_data and return #use this to test plan failsafe api if plan_data.present? && plan_data.is_a?(Hash) if plan_data['price'] == 0 && plan_data['is_external_charge'] == false active_charge_data = plan_obj.get_charge(params[:shop]) begin if active_charge_data && active_charge_data.any? && !active_charge_data['active_charge'].nil? && !active_charge_data['active_charge']['charge_id'].nil? gq_obj = AppManager::GraphqlHelper.new(@shop.shopify_domain, @shop.shopify_token) rec_cancel_data = gq_obj.recurring_charge_cancel_api_call(active_charge_data['active_charge']['charge_id'], @shop) if !rec_cancel_data["errors"].present? && (rec_cancel_data["data"].present? && rec_cancel_data["data"]["appSubscriptionCancel"].present? && !rec_cancel_data["data"]["appSubscriptionCancel"]["userErrors"].any? && (rec_cancel_data["data"]["appSubscriptionCancel"]["appSubscription"]["status"] == 'CANCELLED')) # cancelled_charge_id = rec_cancel_data["data"]["appSubscriptionCancel"]["appSubscription"]["id"].split('/')[-1] shop_plan_id = @shop[AppManager.configuration.plan_id_or_name_field] if !shop_plan_id.nil? plan_obj.cancel_charge(params[:shop], shop_plan_id) end end end rescue Exception => e Rollbar.error("APP MANAGER Process Plan Failed #{e.inspect}-#{e.backtrace}") end @trial_activated_field = AppManager.configuration.field_names['trial_activated_at'] update_info = {@plan_field => params[:plan_id], @trial_activated_field => nil,grandfathered_field => 0} if !config_trial_days.nil? && !plan_data.nil? trial_days = plan_data['trial_days'] || 0 update_info[config_trial_days] = trial_days end if @shop.update(update_info) begin plan_data['old_plan'] = params[:old_plan] || nil; AppManager::EventHandler.new('charge_created', { "plan" => plan_data, "charge" => nil, "previous_charge" => nil, "shopify_domain" => params[:shop] }) rescue Exception => e Rollbar.error("APP MANAGER Error in Process Plan #{e.inspect}-#{e.backtrace}") end AppManager.clear_cache # render json: {'redirect_url' => "#{app_url}?shop=#{params[:shop]}"} and return true render json: {'status' => true,'plan_type' => 'free_plan'} and return true else raise Error, "Invalid charge" end end request_data = {'shop' => @shop.shopify_domain, 'timestamp' => Time.now.to_i, 'plan' => params[:plan_id]} request_data.merge!('host' => params['host']) if params['host'].present? request_data.merge!('old_plan' => params['old_plan']) if params['old_plan'].present? return_url = "#{app_url}#{plan_callback_path}?#{Rack::Utils.build_query(request_data)}" gq_obj = AppManager::GraphqlHelper.new(@shop.shopify_domain, @shop.shopify_token) discount_local_storage = params[:discount_code].present? && !params[:discount_code].nil? ? params[:discount_code] : nil data = gq_obj.recurring_charge_api_call(plan_data, return_url, @shop,discount_local_storage) if data.present? && !data["errors"].present? && (data["data"].present? && data["data"]["appSubscriptionCreate"].present? && (!data["data"]["appSubscriptionCreate"]["userErrors"].any? && data["data"]["appSubscriptionCreate"]["confirmationUrl"])) redirect_charge = data["data"]["appSubscriptionCreate"]["confirmationUrl"] render json: {'redirect_url' => redirect_charge} else raise Error, "#{data.inspect}" end else raise Error, "Plan not found" end else raise ModelNotFound, "Shop not found" end else raise Error, "Missing Shop domain or plan id in params" end end def callback if params[:charge_id].present? && params[:shop].present? && params[:plan].present? @shop = shop_data shopify_token = @field_names['shopify_token'] shopify_domain = @field_names['name'] grandfathered_field = @field_names['grandfathered'] discounted_plans = [] if !@shop.nil? old_plan_id = @shop[@plan_field] old_plan_data = nil headers = {"X-Shopify-Access-Token" => @shop[shopify_token]} charges = HTTParty.get('https://' + @shop[shopify_domain] + '/admin/api/' + @api_version + '/recurring_application_charges/' + params[:charge_id] + '.json', :headers => headers) if charges.parsed_response && charges.parsed_response.is_a?(Hash) && charges.parsed_response.has_key?('recurring_application_charge') plan_obj = AppManager::Client.new plan_data = plan_obj.get_plan(params[:plan], params[:shop]) charge = charges.parsed_response['recurring_application_charge'] charge['charge_id'] = charge['id'] charge['type'] = 'recurring' charge['plan_id'] = params[:plan] charge['shop_domain'] = params[:shop] charge['interval'] = plan_data['interval']['value'] ['api_client_id', 'return_url', 'decorated_return_url','id','id','currency'].each { |k| charge.delete k } charge_ob = AppManager::Client.new(nil, json_req = true) response = charge_ob.store_charge(charge.to_json) if response['message'] == "success" AppManager.clear_cache update_info = {@plan_field => params[:plan],grandfathered_field => 0} if !config_trial_days.nil? && !plan_data.nil? trial_days = plan_data['trial_days'] || 0 update_info[config_trial_days] = trial_days end @shop.update(update_info) Thread.new do charge_data = plan_obj.get_charge(@shop[shopify_domain]) begin AppManager::EventHandler.new('charge_created', { "plan" => plan_data, "charge" => charge, "previous_charge" => charge_data ? (charge_data['cancelled_charge'] || nil) : nil, "shopify_domain" => params[:shop] }) rescue Exception => e Rollbar.error("Error in APP MANAGER Charge Created Callback >>>> #{e.inspect}-#{e.backtrace}") end begin plan_obj = AppManager::Client.new if params[:discount].present? && !params[:discount].nil? && params[:discount] != '0' && !plan_data['is_global'] discounted_plans = plan_obj.get_related_discounted_plans(params[:discount]) if discounted_plans.empty? || discounted_plans.include?(params[:plan].to_i) plan_obj.discount_used(@shop[shopify_domain], params[:discount]) end end rescue Exception => e Rollbar.error("Error in APP MANAGER Discount used API call >>>> #{e.inspect}-#{e.backtrace}") end end end embed_host = Base64.encode64(params[:shop] + "/admin") if !old_plan_id.nil? plan_obj = AppManager::Client.new old_plan_data = plan_obj.get_plan(old_plan_id, params[:shop]) end current_plan_string = !plan_data.nil? ? "#{plan_data['name'].gsub(" ", "-")}-#{plan_data['interval']['label']}" : "none" rescue "" old_plan_string = !old_plan_data.nil? ? "#{old_plan_data['name'].gsub(" ", "-")}-#{old_plan_data['interval']['label']}" : "none" rescue "" plan_query_string = "new_plan=#{current_plan_string}&old_plan=#{old_plan_string}" if app_slug.present? && plan_page_route_value.present? redirect_to "https://#{params[:shop]}/admin/apps/#{app_slug}/#{plan_page_route_value}?#{plan_query_string}" elsif app_slug.present? && !plan_page_route_value.present? redirect_to "https://#{params[:shop]}/admin/apps/#{app_slug}" else redirect_to "#{app_url}?host=#{embed_host}&shop=#{params[:shop]}", :status => 301 and return end else raise Error, "Invalid shopify charge #{charges.inspect}" end else raise ModelNotFound, "Shop not found" end else if params[:shop].present? embed_host = Base64.encode64(params[:shop] + "/admin") if app_slug.present? redirect_to "https://#{params[:shop]}/admin/apps/#{app_slug}" else redirect_to "#{app_url}?host=#{embed_host}&shop=#{params[:shop]}", :status => 301 and return end else raise Error, "Invalid params, must have charge_id,shop && plan in charge controller" end end end def cancel_charge if params[:charge_id].present? && params[:shop].present? @shop = shop_data shopify_token = @field_names['shopify_token'] begin gq_obj = AppManager::GraphqlHelper.new(@shop[@shopify_domain], @shop[shopify_token]) rec_cancel_data = gq_obj.recurring_charge_cancel_api_call(params[:charge_id], @shop) rescue Exception => e Rollbar.error("APP MANAGER Cancel Plan Failed #{e.inspect}-#{e.backtrace}") end end head :ok end def activate_global if params[:shop].present? && params[:plan_id].present? @shop = shop_data grandfathered_field = @field_names['grandfathered'] trial_activated_field = @field_names['trial_activated_at'] if !@shop.nil? plan_obj = AppManager::Client.new plan_data = plan_obj.get_plan(params[:plan_id], params[:shop]) update_info = {@plan_field => params[:plan_id], trial_activated_field => nil,grandfathered_field => 0} if !config_trial_days.nil? && !plan_data.nil? trial_days = plan_data['trial_days'] || 0 update_info[config_trial_days] = trial_days end if @shop.update(update_info) begin plan_data['shop_domain'] = params[:shop]; plan_data['old_plan'] = params[:old_plan] || nil; AppManager::EventHandler.new('charge_created', { "plan" => plan_data, "charge" => nil, "previous_charge" => nil, "shopify_domain" => params[:shop] }) rescue Exception => e Rollbar.error("APP MANAGER Error in Activate Global plan #{e.inspect}-#{e.backtrace}") end AppManager.clear_cache end end render json: {'status' => true,'plan_type' => 'global_plan'} and return true end end def cancel_global if params[:shop].present? @shop = shop_data grandfathered_field = @field_names['grandfathered'] trial_activated_field = @field_names['trial_activated_at'] if !@shop.nil? update_info = {@plan_field => nil, trial_activated_field => nil,grandfathered_field => 0} if !config_trial_days.nil? update_info[config_trial_days] = 0 end @shop.update(update_info) AppManager.clear_cache end render json: {'status' => true,'plan_type' => 'cancel_plan'} and return true end end private def params_permit params.permit! end def model @models = ActiveRecord::Base.connection.tables @config_table = AppManager.configuration.shopify_table_name @shopify_domain = AppManager.configuration.shopify_domain_field @plan_field = AppManager.configuration.plan_id_or_name_field @field_names = AppManager.configuration.field_names @api_version = AppManager.configuration.shopify_api_version if @models.include?(@config_table) && !@plan_field.nil? return @config_table.classify.constantize else return nil end end def shop_data if model return model.where(@shopify_domain => params[:shop]).first rescue nil else return nil end end def app_url AppManager.configuration.app_url end def app_slug AppManager.configuration.shopify_app_slug end def plan_page_route_value AppManager.configuration.plan_page_route end def config_trial_days @field_names = AppManager.configuration.field_names if !@field_names.nil? && @field_names.has_key?('total_trial_days') && !@field_names['total_trial_days'].nil? && !@field_names['total_trial_days'].blank? return @field_names['total_trial_days'] else return nil end end end end