Module: ActsAsPurchasableWizard

Extended by:
ActiveSupport::Concern
Defined in:
app/models/concerns/acts_as_purchasable_wizard.rb

Overview

ActsAsPurchasableWizard

Defined Under Namespace

Modules: Base, ClassMethods

Instance Method Summary collapse

Instance Method Details

#after_submit_purchased!Object



180
181
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 180

def after_submit_purchased!
end

#before_submit_order_save(order) ⇒ Object



93
94
95
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 93

def before_submit_order_save(order)
  order
end

#before_submit_purchased!Object

A hook to extend



177
178
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 177

def before_submit_purchased!
end

#billing!Object

Owner clicks on the Billing step. Next step is Checkout



155
156
157
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 155

def billing!
  ready! && save!
end

#build_submit_fees_and_orderObject

Should be indempotent.



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 124

def build_submit_fees_and_order
  return false if 

  fees = find_or_build_submit_fees()
  raise('already has purchased submit fees') if Array(fees).any?(&:purchased?)

  order = find_or_build_submit_order()
  raise('expected an Effective::Order') unless order.kind_of?(Effective::Order)
  raise('already has purchased submit order') if order.purchased?
  raise('unable to proceed with a voided submit order') if order.try(:voided?)

  true
end

#find_or_build_submit_feesObject



46
47
48
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 46

def find_or_build_submit_fees
  submit_fees
end

#find_or_build_submit_orderObject



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 50

def find_or_build_submit_order
  order = submit_order || orders.build(user: owner) # This is polymorphic user, might be an organization
  order = orders.build(user: owner) if order.declined? # Make a new order, if the previous one was declined

  fees = submit_fees().reject { |fee| fee.marked_for_destruction? }

  # Make sure all Fees are valid
  fees.each do |fee|
    raise("expected a valid fee but #{fee.id} had errors #{fee.errors.inspect}") unless fee.valid?
  end

  # A membership could go from individual to organization
  order.user = owner

  # Adds fees, but does not overwrite any existing price.
  fees.each do |fee|
    order.add(fee) unless order.purchasables.include?(fee)
  end

  order.order_items.each do |order_item|
    fee = fees.find { |fee| fee == order_item.purchasable }
    order.remove(order_item) unless fee.present?
  end

  # From Billing Step
  order.billing_address = owner.billing_address if owner.try(:billing_address).present?

  # This will update all order items to match the prices from their purchasable
  order.try(:update_purchasable_attributes)

  # Handle effective_memberships coupon fees price reduction
  reduce_order_item_coupon_fee_price(order)

  # Hook to extend for coupon fees
  order = before_submit_order_save(order)
  raise('before_submit_order_save must return an Effective::Order') unless order.kind_of?(Effective::Order)

  # Important to add/remove anything
  order.save!

  order
end

#ready!Object

Ready to check out This is called by the “ready_checkout” before_action in wizard_controller/before_actions.rb



161
162
163
164
165
166
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 161

def ready!
  without_current_step do
    build_submit_fees_and_order
    save!
  end
end

#reduce_order_item_coupon_fee_price(order) ⇒ Object

This is used by effective_memberships and effective_events Which both add coupon_fees to their submit_fees



99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 99

def reduce_order_item_coupon_fee_price(order)
  # This only applies to orders with coupon fees
  order_items = order.order_items.select { |oi| oi.purchasable.try(:coupon_fee?) }
  return order unless order_items.present?
  raise('multiple coupon fees not supported') if order_items.length > 1

  # Get the coupon fee
  order_item = order_items.first
  coupon_fee = order_item.purchasable
  raise('expected order item for coupon fee to be a negative price') unless coupon_fee.price.to_i < 0

  # Calculate price
  subtotal = order.order_items.reject { |oi| oi.purchasable.try(:coupon_fee?) }.sum(&:subtotal)

  price = 0 if subtotal <= 0
  price ||= [coupon_fee.price, (0 - subtotal)].max

  # Assign the price to this order item. Underlying fee price stays the same.
  order_item.assign_attributes(price: price)

  # Return the order
  order
end

#submit!Object

Draft -> Submitted requirements



184
185
186
187
188
189
190
191
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 184

def submit!
  raise('already submitted') if 
  raise('expected a purchased order') unless submit_order&.purchased?

  wizard_steps[:checkout] ||= Time.zone.now
  wizard_steps[:submitted] = Time.zone.now
  
end

#submit_feesObject

All Fees and Orders



38
39
40
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 38

def submit_fees
  raise('to be implemented by caller')
end

#submit_orderObject



42
43
44
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 42

def submit_order
  orders.last
end

#submit_purchased!Object

Called automatically via after_purchase hook above



169
170
171
172
173
174
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 169

def submit_purchased!
  return false if 

  wizard_steps[:checkout] = Time.zone.now
  submit!
end

#with_outstanding_coupon_fees(purchasables) ⇒ Object

Called by effective_memberships and effective_events



139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'app/models/concerns/acts_as_purchasable_wizard.rb', line 139

def with_outstanding_coupon_fees(purchasables)
  return purchasables unless owner.respond_to?(:outstanding_coupon_fees) # effective_memberships_owner
  raise('expected has_many fees') unless respond_to?(:fees)

  price = purchasables.reject { |p| p.try(:coupon_fee?) }.map { |p| p.price || 0 }.sum

  if price > 0
    Array(owner.outstanding_coupon_fees).each { |fee| fees << fee unless fees.include?(fee) }
  else
    Array(owner.outstanding_coupon_fees).each { |fee| fees.delete(fee) if fees.include?(fee) }
  end

  (purchasables + fees).uniq
end