Module: EffectiveMembershipsOwner

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

Overview

EffectiveMembershipsOwner

Mark your owner model with effective_memberships_owner to get all the includes

Defined Under Namespace

Modules: Base, ClassMethods

Instance Method Summary collapse

Instance Method Details

#additional_fee_attributes(fee) ⇒ Object

Instance Methods



140
141
142
143
# File 'app/models/concerns/effective_memberships_owner.rb', line 140

def additional_fee_attributes(fee)
  raise('expected an Effective::Fee') unless fee.kind_of?(Effective::Fee)
  {}
end

#assign_member_roleObject



79
80
81
# File 'app/models/concerns/effective_memberships_owner.rb', line 79

def assign_member_role
  membership_present? ? add_role(:member) : remove_role(:member)
end

#bad_standing_feesObject



113
114
115
# File 'app/models/concerns/effective_memberships_owner.rb', line 113

def bad_standing_fees
  fees.select { |fee| fee.bad_standing? }
end

#build_discount_fee(from:, date: nil) ⇒ Object



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'app/models/concerns/effective_memberships_owner.rb', line 166

def build_discount_fee(from:, date: nil)
  raise('must have an existing membership') unless membership.present?
  raise('existing membership category may not be same as from') if membership.category == from

  date ||= Time.zone.now
  price = from.discount_fee(date: date)
  period = EffectiveMemberships.Registrar.period(date: date)
  category = membership.category

  fee = fees.find { |fee| fee.fee_type == 'Discount' && fee.period == period && fee.category == category } || fees.build()
  return fee if fee.purchased?

  fee.assign_attributes(
    fee_type: 'Discount',
    category: category,
    price: price,
    period: period
  )

  fee
end

#build_late_fee(category:, period:) ⇒ Object



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
# File 'app/models/concerns/effective_memberships_owner.rb', line 238

def build_late_fee(category:, period:)
  raise('must have an existing membership') unless membership.present?

  # Return existing but do not build yet
  fee = fees.find { |fee| fee.fee_type == 'Late' && fee.period == period && fee.category_id == category.id && fee.category_type == category.class.name }
  return fee if fee&.purchased?

  # Only continue if there is a late renewal fee for the same period
  renewal_fee = fees.find { |fee| fee.fee_type == 'Renewal' && fee.period == period && fee.category_id == category.id && fee.category_type == category.class.name }
  return unless fee.present? || renewal_fee&.late?

  # Build the late fee
  fee ||= fees.build()

  fee.assign_attributes(
    fee_type: 'Late',
    category: category,
    price: category.late_fee.to_i,
    period: period,
  )

  fee
end

#build_membership_history(start_on: nil) ⇒ Object



288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
# File 'app/models/concerns/effective_memberships_owner.rb', line 288

def build_membership_history(start_on: nil)
  raise('expected membership to be present') unless membership.present?

  # The date of change
  start_on ||= Time.zone.now
  removed = membership.marked_for_destruction?

  # End the other membership histories
  membership_histories.each { |history| history.end_on ||= start_on }

  # Snapshot of the current membership at this time
  membership_histories.build(
    start_on: start_on,
    end_on: nil,
    removed: removed,
    bad_standing: membership.bad_standing?,
    categories: (membership.categories.map(&:to_s) unless removed),
    category_ids: (membership.categories.map(&:id) unless removed),
    number: (membership.number unless removed)
  )
end

#build_prorated_fee(date: nil) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'app/models/concerns/effective_memberships_owner.rb', line 145

def build_prorated_fee(date: nil)
  raise('must have an existing membership') unless membership.present?

  date ||= Time.zone.now
  price = membership.category.prorated_fee(date: date)
  period = EffectiveMemberships.Registrar.period(date: date)
  category = membership.category

  fee = fees.find { |fee| fee.fee_type == 'Prorated' && fee.period == period && fee.category == category } || fees.build()
  return fee if fee.purchased?

  fee.assign_attributes(
    fee_type: 'Prorated',
    category: category,
    price: price,
    period: period
  )

  fee
end

#build_renewal_fee(category:, period:, late_on:, bad_standing_on:) ⇒ Object



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# File 'app/models/concerns/effective_memberships_owner.rb', line 217

def build_renewal_fee(category:, period:, late_on:, bad_standing_on:)
  raise('must have an existing membership') unless membership.present?

  fee = fees.find { |fee| fee.fee_type == 'Renewal' && fee.period == period && fee.category_id == category.id && fee.category_type == category.class.name }
  return fee if fee&.purchased?

  # Build the renewal fee
  fee ||= fees.build()

  fee.assign_attributes(
    fee_type: 'Renewal',
    category: category,
    price: category.renewal_fee.to_i,
    period: period,
    late_on: late_on,
    bad_standing_on: bad_standing_on
  )

  fee
end

#build_title_fee(period:, title:, fee_type: nil, category: nil, price: nil, qb_item_name: nil, tax_exempt: nil) ⇒ Object



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# File 'app/models/concerns/effective_memberships_owner.rb', line 188

def build_title_fee(period:, title:, fee_type: nil, category: nil, price: nil, qb_item_name: nil, tax_exempt: nil)
  fee_type ||= 'Renewal'

  fee = fees.find do |fee|
    fee.fee_type == fee_type && fee.period == period && fee.title == title &&
    (category.blank? || fee.category_id == category.id && fee.category_type == category.class.name)
  end

  return fee if fee&.purchased?

  # Build the title fee
  fee ||= fees.build()
  price ||= (category.renewal_fee.to_i if category.present? && fee_type == 'Renewal')

  fee.assign_attributes(
    fee_type: fee_type,
    title: title,
    category: category,
    price: price,
    period: period,
    qb_item_name: qb_item_name,
    tax_exempt: tax_exempt,
    late_on: nil,
    bad_standing_on: nil
  )

  fee
end

#current_fee_payment_ownerObject



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

def current_fee_payment_owner
  outstanding_fee_payment_owners.first || self
end

#effective_memberships_ownerObject



50
51
52
53
# File 'app/models/concerns/effective_memberships_owner.rb', line 50

def effective_memberships_owner
  raise('expected singular usage but there are more than one owner') if effective_memberships_owners.length > 1
  effective_memberships_owners.first
end

#effective_memberships_ownersObject



55
56
57
58
59
60
61
62
# File 'app/models/concerns/effective_memberships_owner.rb', line 55

def effective_memberships_owners
  owners = organizations if self.class.respond_to?(:effective_organizations_user?)
  owners = users if self.class.respond_to?(:effective_organizations_organization?)

  owners = Array(owners).reject { |owner| owner.try(:archived?) }

  owners.presence || [self]
end

#individual_membership_present?Boolean

Returns:

  • (Boolean)


70
71
72
# File 'app/models/concerns/effective_memberships_owner.rb', line 70

def individual_membership_present?
  membership.present? && !membership.marked_for_destruction?
end

#max_fees_paid_periodObject



117
118
119
# File 'app/models/concerns/effective_memberships_owner.rb', line 117

def max_fees_paid_period
  fees.select { |fee| fee.membership_period_fee? && fee.purchased? }.map(&:period).max
end

#max_fees_paid_through_periodObject



121
122
123
124
# File 'app/models/concerns/effective_memberships_owner.rb', line 121

def max_fees_paid_through_period
  return nil if max_fees_paid_period.blank?
  EffectiveMemberships.Registrar.period_end_on(date: max_fees_paid_period)
end

#membership_fees_paid?Boolean

Returns:

  • (Boolean)


101
102
103
# File 'app/models/concerns/effective_memberships_owner.rb', line 101

def membership_fees_paid?
  outstanding_fee_payment_fees.blank? && membership && membership.fees_paid?
end

#membership_history_on(date) ⇒ Object



310
311
312
313
# File 'app/models/concerns/effective_memberships_owner.rb', line 310

def membership_history_on(date)
  raise('expected a date') unless date.respond_to?(:strftime)
  membership_histories.find { |history| (history.start_on..history.end_on).cover?(date) } # Ruby 2.6 supports endless ranges
end

#membership_present?Boolean

This is the calculated way of determining if an owner is a member or not. The correct way to check for membership is: current_user.is?(:member)

Returns:

  • (Boolean)


66
67
68
# File 'app/models/concerns/effective_memberships_owner.rb', line 66

def membership_present?
  individual_membership_present? || organization_membership_present?
end

#membership_removed?Boolean

Returns:

  • (Boolean)


126
127
128
# File 'app/models/concerns/effective_memberships_owner.rb', line 126

def membership_removed?
  membership.blank? && membership_histories.any? { |history| history.removed? }
end

#membership_removed_onObject



130
131
132
133
# File 'app/models/concerns/effective_memberships_owner.rb', line 130

def membership_removed_on
  return nil unless membership_removed?
  membership_histories.find { |history| history.removed? }.start_on
end

#organization_membership_present?(except: nil) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
# File 'app/models/concerns/effective_memberships_owner.rb', line 74

def organization_membership_present?(except: nil)
  return false unless self.class.respond_to?(:effective_organizations_user?)
  organizations.any? { |organization| organization != except && organization.membership_present? }
end

#outstanding_fee_payment_feesObject



105
106
107
# File 'app/models/concerns/effective_memberships_owner.rb', line 105

def outstanding_fee_payment_fees
  fees.select { |fee| fee.fee_payment_fee? && !fee.purchased? }
end

#outstanding_fee_payment_ordersObject



109
110
111
# File 'app/models/concerns/effective_memberships_owner.rb', line 109

def outstanding_fee_payment_orders
  orders.select { |order| order.parent_type.to_s.include?('FeePayment') && !order.purchased? }
end

#outstanding_fee_payment_ownersObject



89
90
91
# File 'app/models/concerns/effective_memberships_owner.rb', line 89

def outstanding_fee_payment_owners
  effective_memberships_owners.select { |owner| !owner.membership_fees_paid? }
end

#owner_labelObject



97
98
99
# File 'app/models/concerns/effective_memberships_owner.rb', line 97

def owner_label
  self.class.name.split('::').last
end

#registrar_action_categories(action) ⇒ Object



135
136
137
# File 'app/models/concerns/effective_memberships_owner.rb', line 135

def registrar_action_categories(action)
  EffectiveMemberships.Category.sorted.all
end

#update_member_role!Object

This can be called by a script to recalculate the owner role based on current membership



84
85
86
87
# File 'app/models/concerns/effective_memberships_owner.rb', line 84

def update_member_role!
  assign_member_role
  save!
end

#update_membership_status!Object

Called by the registrar.



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'app/models/concerns/effective_memberships_owner.rb', line 263

def update_membership_status!
  raise('expected membership to be present') unless membership.present?

  # Assign fees paid through period
  membership.fees_paid_period = max_fees_paid_period()
  membership.fees_paid_through_period = max_fees_paid_through_period()

  # Assign in bad standing
  if membership.bad_standing_admin?
    # Nothing to do
  elsif bad_standing_fees.present?
    membership.bad_standing = true
    membership.bad_standing_reason = 'Unpaid Fees'
  else
    membership.bad_standing = false
    membership.bad_standing_reason = nil
  end

  if membership.bad_standing_changed? || membership_histories.blank?
    build_membership_history()
  end

  save!
end