Class: Gold::Billing

Inherits:
ApplicationRecord
  • Object
show all
Includes:
Statesman::Adapters::ActiveRecordQueries
Defined in:
app/models/gold/billing.rb

Overview

Class that tracks all billing details. Intended to be associated with a shop class that the app uses

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.initial_stateObject



14
15
16
# File 'app/models/gold/billing.rb', line 14

def initial_state
  :new
end

.lookup_for_domain!(domain) ⇒ Object

Finds a billing instance for a particular shop, using the shop’s domain as the key to look it up. Because this is not stored in the Billing model, a join against the shop association is required.



21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'app/models/gold/billing.rb', line 21

def lookup_for_domain!(domain)
  # This is a little bit hard to follow, but `#joins` uses the name of the
  # association as defined below as "shop" and `#where` expects the name
  # of the associated table, which we can query from the class using
  # `#table_name`.
  joins(:shop)
    .where(
      Gold.shop_class.table_name => {
        Gold.shop_domain_attribute => domain
      }
    )
    .first!
end

.transition_classObject



10
11
12
# File 'app/models/gold/billing.rb', line 10

def transition_class
  Gold::Transition
end

Instance Method Details

#after_shop_update!Object

Provides a way to let Gold know that the shop has changed. Your app should call this whenever a new shop update webhook is received or is manually overridden



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'app/models/gold/billing.rb', line 110

def after_shop_update!
  return_url = Engine.routes.url_helpers.process_charge_url

  Gold.logger.info("Received shop update from '#{shop.shopify_domain}'")

  shop.with_shopify_session do
    case current_state
    when :affiliate
      if shopify_plan.paying?
        # If an affiliate has converted, change them to a paid plan
        ConvertAffiliateToPaidOp.new(self, return_url).call
      end
    when :billing
      # If their plan has been frozen, move to frozen state
      FreezeOp.new(self).call if can_transition_to?(:frozen)
    when :frozen
      CheckChargeOp.new(self).call unless shopify_plan.frozen?
    end
  end
end

#app_access?Boolean

Shops within these states should not get access to the app or services

Returns:

  • (Boolean)


132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'app/models/gold/billing.rb', line 132

def app_access?
  blacklist = %i[
    new
    accepted_terms
    select_tier
    sudden_charge
    sudden_charge_declined
    sudden_charge_expired
    marked_as_suspended
    suspended
    frozen
    delinquent
    marked_as_uninstalled
    uninstalled
    cleanup
    done
  ]

  !blacklist.include?(current_state)
end

#calculate_price(tier) ⇒ Object



104
105
106
# File 'app/models/gold/billing.rb', line 104

def calculate_price(tier)
  tier.monthly_price * (100 - discount_percentage) / 100
end

#calculate_trial_days(tier, now = Time.current) ⇒ Object



85
86
87
88
89
90
91
92
93
94
# File 'app/models/gold/billing.rb', line 85

def calculate_trial_days(tier, now = Time.current)
  starts_at = trial_starts_at || now
  trial_ends_at = starts_at.advance(days: tier.trial_days)
  trial_period = trial_ends_at - now
  if trial_period > 0
    (trial_period / 1.day).ceil
  else
    0
  end
end

#last_selected_tierObject



70
71
72
# File 'app/models/gold/billing.rb', line 70

def last_selected_tier
  @last_selected_tier ||= find_last_selected_tier
end

#qualifies_for_tier?(tier) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
# File 'app/models/gold/billing.rb', line 96

def qualifies_for_tier?(tier)
  shop ? shop.qualifies_for_tier?(tier) : true
end

#shopify_planObject

Returns the Shopify plan for this shop.



75
76
77
78
79
80
81
82
83
# File 'app/models/gold/billing.rb', line 75

def shopify_plan
  if shopify_plan_override
    ShopifyPlan.new(shopify_plan_override)
  elsif shop
    ShopifyPlan.new(shop.shopify_plan_name)
  else
    ShopifyPlan.new(ShopifyAPI::Shop.current.plan_name)
  end
end

#state_machineObject

rubocop:enable Rails/ReflectionClassName



47
48
49
50
51
# File 'app/models/gold/billing.rb', line 47

def state_machine
  transition_class = self.class.transition_class
  @state_machine ||= Machine.new(self, transition_class: transition_class,
                                       association_name: :transitions)
end

#tierObject



61
62
63
# File 'app/models/gold/billing.rb', line 61

def tier
  @tier ||= Tier.find(tier_id)
end

#tier=(tier) ⇒ Object



65
66
67
68
# File 'app/models/gold/billing.rb', line 65

def tier=(tier)
  @tier = tier
  self[:tier_id] = tier.id
end

#trial_days_leftObject



100
101
102
# File 'app/models/gold/billing.rb', line 100

def trial_days_left
  calculate_trial_days(tier)
end