module ShopifyApp::EnsureBilling
def billing_required?
def billing_required? ShopifyApp.configuration.requires_billing? end
def check_billing(session = current_shopify_session)
def check_billing(session = current_shopify_session) return true if session.blank? || !billing_required? confirmation_url = nil if has_active_payment?(session) has_payment = true else has_payment = false confirmation_url = request_payment(session) end unless has_payment if request.xhr? add_top_level_redirection_headers(url: confirmation_url, ignore_response_code: true) ShopifyApp::Logger.debug("Responding with 401 unauthorized") head(:unauthorized) elsif ShopifyApp.configuration.embedded_app? fullpage_redirect_to(confirmation_url) else redirect_to(confirmation_url, allow_other_host: true) end end has_payment end
def handle_billing_error(error)
def handle_billing_error(error) logger.info("#{error.message}: #{error.errors}") redirect_to_login end
def has_active_payment?(session)
def has_active_payment?(session) if recurring? has_subscription?(session) else has_one_time_payment?(session) end end
def has_one_time_payment?(session)
def has_one_time_payment?(session) ShopifyApp::Logger.debug("Checking if has one time payment") purchases = nil end_cursor = nil loop do response = run_query(session: session, query: ONE_TIME_PURCHASES_QUERY, variables: { endCursor: end_cursor }) purchases = response.body["data"]["currentAppInstallation"]["oneTimePurchases"] purchases["edges"].each do |purchase| node = purchase["node"] if node["name"] == ShopifyApp.configuration.billing.charge_name && (!Rails.env.production? || !node["test"]) && node["status"] == "ACTIVE" return true end end end_cursor = purchases["pageInfo"]["endCursor"] break unless purchases["pageInfo"]["hasNextPage"] end false end
def has_subscription?(session)
def has_subscription?(session) ShopifyApp::Logger.debug("Checking if shop has subscription") response = run_query(session: session, query: RECURRING_PURCHASES_QUERY) subscriptions = response.body["data"]["currentAppInstallation"]["activeSubscriptions"] subscriptions.each do |subscription| if subscription["name"] == ShopifyApp.configuration.billing.charge_name && (!Rails.env.production? || !subscription["test"]) return true end end false end
def recurring?
def recurring? RECURRING_INTERVALS.include?(ShopifyApp.configuration.billing.interval) end
def request_one_time_payment(session:, return_url:)
def request_one_time_payment(session:, return_url:) response = run_query( session: session, query: ONE_TIME_PURCHASE_MUTATION, variables: { name: ShopifyApp.configuration.billing.charge_name, price: { amount: ShopifyApp.configuration.billing.amount, currencyCode: ShopifyApp.configuration.billing.currency_code, }, returnUrl: return_url, test: ShopifyApp.configuration.billing.test, }, ) response.body end
def request_payment(session)
def request_payment(session) shop = session.shop host = Base64.encode64("#{shop}/admin") return_url = "#{ShopifyAPI::Context.host}?shop=#{shop}&host=#{host}" if recurring? data = request_recurring_payment(session: session, return_url: return_url) data = data["data"]["appSubscriptionCreate"] else data = request_one_time_payment(session: session, return_url: return_url) data = data["data"]["appPurchaseOneTimeCreate"] end raise BillingError.new("Error while billing the store", data["userErrors"]) unless data["userErrors"].empty? data["confirmationUrl"] end
def request_recurring_payment(session:, return_url:)
def request_recurring_payment(session:, return_url:) response = run_query( session: session, query: RECURRING_PURCHASE_MUTATION, variables: { name: ShopifyApp.configuration.billing.charge_name, lineItems: { plan: { appRecurringPricingDetails: { interval: ShopifyApp.configuration.billing.interval, price: { amount: ShopifyApp.configuration.billing.amount, currencyCode: ShopifyApp.configuration.billing.currency_code, }, }, }, }, returnUrl: return_url, trialDays: ShopifyApp.configuration.billing.trial_days, test: ShopifyApp.configuration.billing.test, }, ) response.body end
def run_query(session:, query:, variables: nil)
def run_query(session:, query:, variables: nil) client = ShopifyAPI::Clients::Graphql::Admin.new(session: session) response = client.query(query: query, variables: variables) raise BillingError.new("Error while billing the store", []) unless response.ok? raise BillingError.new("Error while billing the store", response.body["errors"]) if response.body["errors"] response end