effective_memberships 0.17.7 → 0.17.9

Sign up to get free protection for your applications and to get access to all the features.
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