effective_memberships 0.17.7 → 0.17.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a1c595c47725e74e8e78cd82360ca33ef5bb778a47f217ecfa6fb8a30452df6b
4
- data.tar.gz: 41f45a5ac18a4c0f6448620e6c0b1bcfd6c937028c28783b7b35225a620496f6
3
+ metadata.gz: 7a7ab7d95194d5d7c49af9f4d8297b4a9f927f9d4a2d97ea2f18ead660488685
4
+ data.tar.gz: 7412d96bc6f4b1c7329a3fa2b4998e0045d921f1deec09886f024f42b868afc7
5
5
  SHA512:
6
- metadata.gz: c6d24ab45dfce8b8e8f4efd2c93ca865408f2a3c4de8db61b9c0163cc750d22b5eb955bcc1bb0ea6d2cd4f9905707902bbd89d56c95bec9a17e4e02098e52adf
7
- data.tar.gz: 132237106d797e86db32d255ae35404ca34ea140879cc51d6445705e20fbbbf61f94f016cc2fd02e31629d139daf808a036812626b7af54e0523c44d777c399e
6
+ metadata.gz: 6aeaa23fda513f0b707252be4009fa6b25c19a8ee9f7ead8761a15893fa5b56a2b1ddba20da408e42f5d8c7759dc1b53c9faba19b20eecac28b5dfdf863c8703
7
+ data.tar.gz: d2abd9350b5b98b43db54214b9cdf4a8fdc40858a66a4ea8f0ad301870326d16892287ad5ae1ac4a8dda70db2545e0d4ed12092e2bf265b3ae249137323bc311
@@ -64,7 +64,13 @@ module Admin
64
64
  membership.owner.try(:addresses).try(:first).try(:postal_code)
65
65
  end
66
66
 
67
- actions_col
67
+ actions_col do |membership|
68
+ if membership.owner_type.include?('Organization')
69
+ dropdown_link_to 'Show', "/admin/organizations/#{membership.owner.to_param}/edit#tab-membership", 'data-turbolinks': false
70
+ elsif membership.owner_type.include?('User')
71
+ dropdown_link_to 'Show', "/admin/users/#{membership.owner.to_param}/edit#tab-membership", 'data-turbolinks': false
72
+ end
73
+ end
68
74
  end
69
75
 
70
76
  collection do
@@ -192,7 +192,7 @@ module EffectiveMembershipsApplicant
192
192
 
193
193
  # effective_reports
194
194
  def reportable_scopes
195
- { draft: nil, submitted: nil, in_progress: nil, done: nil }
195
+ { draft: nil, submitted: nil, missing_info: nil, completed: nil, reviewed: nil, declined: nil, approved: nil, in_progress: nil, done: nil }
196
196
  end
197
197
 
198
198
  scope :deep, -> { includes(:user, :organization, :category, :from_category, :from_status, :orders) }
@@ -202,7 +202,6 @@ module EffectiveMembershipsApplicant
202
202
  scope :done, -> { where(status: [:approved, :declined]) }
203
203
 
204
204
  scope :not_draft, -> { where.not(status: :draft) }
205
-
206
205
  scope :reviewable, -> { where.not(status: [:draft, :submitted, :declined, :approved]) }
207
206
 
208
207
  scope :for, -> (user) {
@@ -251,6 +250,23 @@ module EffectiveMembershipsApplicant
251
250
  validates :category, presence: true
252
251
  end
253
252
 
253
+ # Select Step - Check for expired reclassification or reinstatement dates
254
+ validate(if: -> { current_step == :select && owner.present? && applicant_type.present? && category.present? }) do
255
+ # Dates
256
+ today = (created_at || Time.zone.now).beginning_of_day
257
+
258
+ reclassification_expires_on = owner.reclassification_expires_on(from: from_category, to: category)
259
+ reinstatement_expires_on = owner.reinstatement_expires_on(from: from_status)
260
+
261
+ if reclassification? && reclassification_expires_on.present? && reclassification_expires_on <= today
262
+ errors.add(:base, "Your ability to apply for reclassification expired on #{reclassification_expires_on.strftime('%F')}. Please contact us for assistance.")
263
+ end
264
+
265
+ if reinstatement? && reinstatement_expires_on.present? && reinstatement_expires_on <= today
266
+ errors.add(:base, "Your ability to apply for reinstatement expired on #{reinstatement_expires_on.strftime('%F')}. Please contact us for assistance.")
267
+ end
268
+ end
269
+
254
270
  # They can checkout with outstanding fees
255
271
  # validate(if: -> { current_step == :select && owner.present? }) do
256
272
  # self.errors.add(:base, 'may not have outstanding fees') if owner.outstanding_fee_payment_fees.present?
@@ -29,6 +29,7 @@ module EffectiveMembershipsApplicantReview
29
29
 
30
30
  included do
31
31
  log_changes(to: :applicant) if respond_to?(:log_changes)
32
+ acts_as_reportable if respond_to?(:acts_as_reportable)
32
33
 
33
34
  acts_as_tokened
34
35
 
@@ -59,6 +60,15 @@ module EffectiveMembershipsApplicantReview
59
60
  timestamps
60
61
  end
61
62
 
63
+ # effective_reports
64
+ def reportable_scopes
65
+ { in_progress: nil, done: nil }
66
+ end
67
+
68
+ def reportable_email
69
+ reviewer.try(:email)
70
+ end
71
+
62
72
  scope :deep, -> { includes(:reviewer, applicant: [:user, :applicant_reviews]) }
63
73
 
64
74
  scope :for, -> (user) {
@@ -313,4 +313,8 @@ module EffectiveMembershipsCategory
313
313
  nil
314
314
  end
315
315
 
316
+ def reclassification_expires_in
317
+ nil # 2.years
318
+ end
319
+
316
320
  end
@@ -137,6 +137,44 @@ module EffectiveMembershipsOwner
137
137
  removed_membership_history.start_on if membership_removed?
138
138
  end
139
139
 
140
+ # Checked by the applicant on the select step
141
+ def reclassification_expires_on(from: nil, to: nil)
142
+ return unless membership.present?
143
+
144
+ # User/owner might respond to this
145
+ date = try(:admin_reclassification_expires_on)
146
+ return date if date.present?
147
+
148
+ # When we last reclassified to our current category
149
+ history = last_membership_history(category: membership.membership_categories.first)
150
+ reclassified_on = (history&.start_on || membership.registration_on || membership.joined_on)
151
+
152
+ # Otherwise consider the membership categories
153
+ expires_on = membership.categories.select { |category| category.reclassification_expires_in.present? }.map do |category|
154
+ reclassified_on + category.reclassification_expires_in
155
+ end.min
156
+
157
+ expires_on
158
+ end
159
+
160
+ def reinstatement_expires_on(from: nil)
161
+ return unless membership_removed?
162
+
163
+ # User/owner might respond to this
164
+ date = try(:admin_reinstatement_expires_on)
165
+ return date if date.present?
166
+
167
+ # When we were removed
168
+ removed_on = removed_membership_history.start_on
169
+
170
+ # Consider any membership statuses that have reinstatement expires in
171
+ expires_on = removed_membership_history.membership_statuses.select { |status| status.reinstatement_expires_in.present? }.map do |status|
172
+ removed_on + status.reinstatement_expires_in
173
+ end.min
174
+
175
+ expires_on
176
+ end
177
+
140
178
  # The membership history that is removed. Has exit statuses that may affect reinstatement fees.
141
179
  def removed_membership_history
142
180
  membership_histories.reverse.find { |history| history.removed? } if membership_removed?
@@ -444,6 +482,14 @@ module EffectiveMembershipsOwner
444
482
  membership_histories.find { |history| (history.start_on..history.end_on).cover?(date) } # Ruby 2.6 supports endless ranges
445
483
  end
446
484
 
485
+ def first_membership_history(category: nil)
486
+ membership_histories.find { |history| category.blank? || history.membership_category_ids.include?(category.id) }
487
+ end
488
+
489
+ def last_membership_history(category: nil)
490
+ membership_histories.reverse.find { |history| category.blank? || history.membership_category_ids.include?(category.id) }
491
+ end
492
+
447
493
  # Point out busted data
448
494
  def membership_history_errors
449
495
  return unless membership.present?
@@ -76,9 +76,8 @@ module EffectiveMembershipsStatus
76
76
  title == 'Not In Good Standing'
77
77
  end
78
78
 
79
- # Used for Apply to Join Reinstatement
80
- def reinstatable?
81
- true
79
+ def reinstatement_expires_in
80
+ nil # 2.years
82
81
  end
83
82
 
84
83
  end
@@ -11,6 +11,7 @@ module Effective
11
11
  )
12
12
 
13
13
  log_changes(to: :applicant) if respond_to?(:log_changes)
14
+ acts_as_reportable if respond_to?(:acts_as_reportable)
14
15
 
15
16
  belongs_to :applicant, polymorphic: true, optional: true
16
17
 
@@ -52,6 +53,20 @@ module Effective
52
53
  timestamps
53
54
  end
54
55
 
56
+ # effective_reports
57
+ def reportable_scopes
58
+ { in_progress: nil, done: nil, expired: nil }
59
+ end
60
+
61
+ scope :in_progress, -> { with_submitted_applicants.where(status: :submitted) }
62
+ scope :done, -> { where(status: :completed) }
63
+
64
+ scope :expired, -> { where(status: :submitted).where.not(with_submitted_applicants) }
65
+
66
+ scope :with_submitted_applicants, -> {
67
+ where(applicant_id: EffectiveMemberships.Applicant.submitted)
68
+ }
69
+
55
70
  scope :deep, -> { all }
56
71
 
57
72
  # All step validations
@@ -11,6 +11,7 @@ module Effective
11
11
  has_many :membership_statuses, -> { order(:id) }, inverse_of: :membership, dependent: :delete_all
12
12
  accepts_nested_attributes_for :membership_statuses
13
13
 
14
+ acts_as_reportable if respond_to?(:acts_as_reportable)
14
15
  log_changes(to: :owner) if respond_to?(:log_changes)
15
16
 
16
17
  effective_resource do
@@ -35,7 +36,23 @@ module Effective
35
36
  scope :deep, -> { includes(:owner, membership_categories: :category, membership_statuses: :status) }
36
37
  scope :sorted, -> { order('lower(owner_name)') }
37
38
 
39
+ # effective_reports
40
+ def reportable_scopes
41
+ {
42
+ with_category: :string,
43
+ with_status: :string,
44
+ joined_before: :date,
45
+ joined_after: :date,
46
+ with_paid_fees_through: :date,
47
+ with_unpaid_fees_through: :date,
48
+ in_good_standing: nil,
49
+ not_in_good_standing: nil
50
+ }
51
+ end
52
+
38
53
  scope :with_status, -> (statuses) {
54
+ statuses = Resource.new(EffectiveMemberships.Status).search_any(statuses) if statuses.kind_of?(String)
55
+
39
56
  raise('expected an EffectiveMemberships.Status') unless statuses.class.respond_to?(:effective_memberships_status?) || Array(statuses).all? { |status| status.kind_of?(EffectiveMemberships.Status) }
40
57
  where(id: MembershipStatus.where(status_id: statuses).select(:membership_id))
41
58
  }
@@ -46,6 +63,8 @@ module Effective
46
63
  }
47
64
 
48
65
  scope :with_category, -> (categories) {
66
+ categories = Resource.new(EffectiveMemberships.Category).search_any(categories) if categories.kind_of?(String)
67
+
49
68
  raise('expected an EffectiveMemberships.Category') unless categories.class.respond_to?(:effective_memberships_category?) || Array(categories).all? { |cat| cat.kind_of?(EffectiveMemberships.Category) }
50
69
  where(id: MembershipCategory.where(category_id: categories).select(:membership_id))
51
70
  }
@@ -2,6 +2,8 @@ module Effective
2
2
  class MembershipHistory < ActiveRecord::Base
3
3
  belongs_to :owner, polymorphic: true
4
4
 
5
+ acts_as_reportable if respond_to?(:acts_as_reportable)
6
+
5
7
  effective_resource do
6
8
  start_on :date
7
9
  end_on :date
@@ -13,20 +15,32 @@ module Effective
13
15
  categories :text
14
16
  category_ids :text
15
17
 
18
+ statuses :text
19
+ status_ids :text
20
+
16
21
  notes :text
17
22
 
18
23
  timestamps
19
24
  end
20
25
 
26
+ # TODO: Rename categories to be category_toses
27
+ # And membreship_categories below should be called categories
28
+
21
29
  serialize :categories, Array
22
30
  serialize :category_ids, Array
23
31
 
24
32
  serialize :statuses, Array
25
33
  serialize :status_ids, Array
26
34
 
35
+ # effective_reports
36
+ def reportable_scopes
37
+ { removed: nil, not_removed: nil }
38
+ end
39
+
27
40
  scope :deep, -> { includes(:owner) }
28
41
  scope :sorted, -> { order(:start_on).order(:id) }
29
42
 
43
+ scope :not_removed, -> { where(removed: false) }
30
44
  scope :removed, -> { where(removed: true) }
31
45
 
32
46
  validates :owner, presence: true
@@ -9,6 +9,8 @@
9
9
 
10
10
  = f.static_field :current_action, label: 'Current Membership' do
11
11
  = membership.to_s
12
+ = render('effective/memberships/reclassification', user: membership.owner)
13
+ = render('effective/memberships/reinstatement', user: membership.owner)
12
14
 
13
15
  = f.check_box :current_action, label: 'Yes, update membership information'
14
16
 
@@ -33,11 +33,14 @@
33
33
  - if membership.not_in_good_standing?
34
34
  %p Your membership is Not In Good Standing because of unpurchased fees or dues. Please purchase these dues or contact us.
35
35
 
36
+ - if membership.present?
37
+ = render('effective/memberships/reclassification', user: current_user)
38
+
36
39
  - if current_user.membership_removed?
37
40
  %p Your membership was removed on #{current_user.membership_removed_on.strftime('%F')}.
38
41
 
39
42
  - if current_user.reinstatement_membership_history.present?
40
- %p You may Apply for Reinstatement to #{current_user.reinstatement_membership_category} by clicking the Apply to Join button below and then complete the wizard.
43
+ = render('effective/memberships/reinstatement', user: current_user)
41
44
 
42
45
  - if membership_organizations.present?
43
46
  %p You are a representative for #{pluralize(membership_organizations.length, 'member organization')}.
@@ -0,0 +1,14 @@
1
+ - if user.membership.present?
2
+ - now = Time.zone.now.beginning_of_day
3
+ - applicants = user.applicants.select { |applicant| applicant.in_progress? }
4
+
5
+ - if applicants.blank?
6
+ - expires_on = user.reclassification_expires_on
7
+ - category = user.membership.categories.to_sentence
8
+
9
+ - if expires_on.blank?
10
+ - # Nothing to do
11
+ - elsif now < expires_on
12
+ %p You have until #{expires_on.strftime('%F')}, #{distance_of_time_in_words(now, expires_on)} from now, to Apply for Reclassification from #{category}.
13
+ - else
14
+ %p Your ability to Apply for Reclassification from #{category} expired on #{expires_on.strftime('%F')}.
@@ -0,0 +1,14 @@
1
+ - if user.reinstatement_membership_history.present?
2
+ - now = Time.zone.now.beginning_of_day
3
+ - applicants = user.applicants.select { |applicant| applicant.in_progress? }
4
+
5
+ - if applicants.blank?
6
+ - category = user.reinstatement_membership_category
7
+ - expires_on = user.reinstatement_expires_on
8
+
9
+ - if expires_on.blank?
10
+ - # Nothing to do
11
+ - elsif now < expires_on
12
+ %p You have until #{expires_on.strftime('%F')}, #{distance_of_time_in_words(now, expires_on)} from now, to Apply for Reinstatement to #{category}.
13
+ - else
14
+ %p Your ability to Apply for Reinstatement to #{category} expired on #{expires_on.strftime('%F')}.
@@ -1,3 +1,3 @@
1
1
  module EffectiveMemberships
2
- VERSION = '0.17.7'
2
+ VERSION = '0.17.9'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_memberships
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.7
4
+ version: 0.17.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-05-15 00:00:00.000000000 Z
11
+ date: 2023-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -525,6 +525,8 @@ files:
525
525
  - app/views/effective/membership_directory/show.html.haml
526
526
  - app/views/effective/memberships/_dashboard.html.haml
527
527
  - app/views/effective/memberships/_membership.html.haml
528
+ - app/views/effective/memberships/_reclassification.html.haml
529
+ - app/views/effective/memberships/_reinstatement.html.haml
528
530
  - app/views/effective/memberships_mailer/applicant_approved.liquid
529
531
  - app/views/effective/memberships_mailer/applicant_completed.liquid
530
532
  - app/views/effective/memberships_mailer/applicant_declined.liquid