effective_memberships 0.3.13 → 0.4.1

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.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/admin/organizations_controller.rb +19 -0
  3. data/app/controllers/admin/representatives_controller.rb +19 -0
  4. data/app/controllers/effective/applicants_controller.rb +2 -3
  5. data/app/controllers/effective/fee_payments_controller.rb +1 -2
  6. data/app/controllers/effective/organizations_controller.rb +16 -0
  7. data/app/controllers/effective/representatives_controller.rb +19 -0
  8. data/app/datatables/admin/effective_applicants_datatable.rb +10 -5
  9. data/app/datatables/admin/effective_categories_datatable.rb +7 -0
  10. data/app/datatables/admin/effective_fee_payments_datatable.rb +11 -6
  11. data/app/datatables/admin/effective_organizations_datatable.rb +31 -0
  12. data/app/datatables/admin/effective_representatives_datatable.rb +28 -0
  13. data/app/datatables/effective_applicants_datatable.rb +1 -1
  14. data/app/datatables/effective_fee_payments_datatable.rb +5 -4
  15. data/app/datatables/effective_organizations_datatable.rb +18 -0
  16. data/app/datatables/effective_representatives_datatable.rb +40 -0
  17. data/app/helpers/effective_memberships_helper.rb +25 -0
  18. data/app/mailers/effective/memberships_mailer.rb +34 -15
  19. data/app/models/concerns/effective_memberships_applicant.rb +63 -30
  20. data/app/models/concerns/effective_memberships_category.rb +32 -5
  21. data/app/models/concerns/effective_memberships_fee_payment.rb +44 -45
  22. data/app/models/concerns/effective_memberships_organization.rb +94 -0
  23. data/app/models/concerns/effective_memberships_owner.rb +0 -55
  24. data/app/models/concerns/effective_memberships_registrar.rb +5 -3
  25. data/app/models/concerns/effective_memberships_user.rb +70 -0
  26. data/app/models/effective/fee.rb +1 -1
  27. data/app/models/effective/organization.rb +8 -0
  28. data/app/models/effective/registrar_action.rb +16 -1
  29. data/app/models/effective/representative.rb +56 -0
  30. data/app/views/admin/categories/_form_applicant_eligibility.html.haml +1 -1
  31. data/app/views/admin/categories/_form_applicant_steps.html.haml +29 -24
  32. data/app/views/admin/categories/_form_category.html.haml +3 -0
  33. data/app/views/admin/categories/_form_renewals.html.haml +0 -2
  34. data/app/views/admin/organizations/_fields.html.haml +6 -0
  35. data/app/views/admin/organizations/_form.html.haml +31 -0
  36. data/app/views/admin/organizations/_form_organization.html.haml +23 -0
  37. data/app/views/admin/registrar_actions/_form_fees_paid.html.haml +16 -0
  38. data/app/views/admin/representatives/_form.html.haml +38 -0
  39. data/app/views/{effective/applicants/_demographics_fields.html.haml → admin/representatives/_user_fields.html.haml} +2 -6
  40. data/app/views/effective/applicants/_dashboard.html.haml +24 -5
  41. data/app/views/effective/applicants/_demographics.html.haml +1 -1
  42. data/app/views/effective/applicants/_missing_info.html.haml +7 -3
  43. data/app/views/effective/applicants/_organization.html.haml +9 -0
  44. data/app/views/effective/applicants/_select_organization.html.haml +21 -0
  45. data/app/views/effective/applicants/_summary.html.haml +17 -9
  46. data/app/views/effective/applicants/billing.html.haml +2 -2
  47. data/app/views/effective/applicants/demographics.html.haml +7 -6
  48. data/app/views/effective/applicants/education.html.haml +2 -2
  49. data/app/views/effective/applicants/organization.html.haml +19 -0
  50. data/app/views/effective/applicants/references.html.haml +1 -1
  51. data/app/views/effective/applicants/select.html.haml +11 -1
  52. data/app/views/effective/applicants/stamp.html.haml +2 -2
  53. data/app/views/effective/applicants/start.html.haml +17 -11
  54. data/app/views/effective/applicants/submitted.html.haml +5 -5
  55. data/app/views/effective/applicants/summary.html.haml +1 -1
  56. data/app/views/effective/fee_payments/_demographics.html.haml +1 -1
  57. data/app/views/effective/fee_payments/_organization.html.haml +9 -0
  58. data/app/views/effective/fee_payments/_summary.html.haml +39 -1
  59. data/app/views/effective/fee_payments/billing.html.haml +2 -2
  60. data/app/views/effective/fee_payments/demographics.html.haml +2 -2
  61. data/app/views/effective/fee_payments/organization.html.haml +18 -0
  62. data/app/views/effective/fee_payments/start.html.haml +20 -17
  63. data/app/views/effective/fee_payments/submitted.html.haml +10 -3
  64. data/app/views/effective/fees/_dashboard.html.haml +20 -8
  65. data/app/views/effective/memberships/_dashboard.html.haml +16 -5
  66. data/app/views/effective/organizations/_dashboard.html.haml +10 -0
  67. data/app/views/effective/organizations/_form.html.haml +8 -0
  68. data/app/views/effective/organizations/_form_organization.html.haml +11 -0
  69. data/app/views/effective/representatives/_form.html.haml +33 -0
  70. data/app/views/effective/{fee_payments/_demographics_fields.html.haml → representatives/_user_fields.html.haml} +2 -6
  71. data/app/views/organizations/_demographics.html.haml +45 -0
  72. data/app/views/organizations/_fields_demographics.html.haml +29 -0
  73. data/app/views/users/_demographics.html.haml +50 -0
  74. data/app/views/users/_fields_demographics.html.haml +29 -0
  75. data/config/effective_memberships.rb +4 -0
  76. data/config/routes.rb +9 -0
  77. data/db/migrate/01_create_effective_memberships.rb.erb +57 -10
  78. data/db/seeds.rb +18 -0
  79. data/lib/effective_memberships/engine.rb +3 -0
  80. data/lib/effective_memberships/version.rb +1 -1
  81. data/lib/effective_memberships.rb +7 -3
  82. metadata +33 -20
  83. data/app/views/effective/applicants/_demographics_owner.html.haml +0 -20
  84. data/app/views/effective/fee_payments/_demographics_owner.html.haml +0 -20
@@ -44,7 +44,8 @@ module EffectiveMembershipsApplicant
44
44
  acts_as_wizard(
45
45
  start: 'Start',
46
46
  select: 'Select Application Type',
47
- demographics: 'Demographics',
47
+ demographics: 'Demographics', # Individual only. Users fields.
48
+ organization: 'Organization', # Organization only. Organization fields.
48
49
  education: 'Education',
49
50
  course_amounts: 'Courses',
50
51
  experience: 'Work Experience',
@@ -73,8 +74,11 @@ module EffectiveMembershipsApplicant
73
74
  attr_accessor :approved_membership_date
74
75
 
75
76
  # Application Namespace
76
- belongs_to :owner, polymorphic: true
77
- accepts_nested_attributes_for :owner
77
+ belongs_to :user, polymorphic: true
78
+ accepts_nested_attributes_for :user
79
+
80
+ belongs_to :organization, polymorphic: true, optional: true
81
+ accepts_nested_attributes_for :organization
78
82
 
79
83
  belongs_to :category, polymorphic: true, optional: true
80
84
  belongs_to :from_category, polymorphic: true, optional: true
@@ -142,7 +146,7 @@ module EffectiveMembershipsApplicant
142
146
  timestamps
143
147
  end
144
148
 
145
- scope :deep, -> { includes(:owner, :category, :from_category, :orders) }
149
+ scope :deep, -> { includes(:user, :organization, :category, :from_category, :orders) }
146
150
  scope :sorted, -> { order(:id) }
147
151
 
148
152
  scope :in_progress, -> { where.not(status: [:approved, :declined]) }
@@ -150,14 +154,15 @@ module EffectiveMembershipsApplicant
150
154
 
151
155
  scope :not_draft, -> { where.not(status: :draft) }
152
156
 
153
- # Set Apply to Join or Reclassification
154
- before_validation(if: -> { new_record? && owner.present? }) do
155
- self.applicant_type ||= (owner.membership.blank? ? 'Apply to Join' : 'Apply to Reclassify')
156
- self.from_category ||= owner.membership&.category
157
- end
157
+ scope :for, -> (user) {
158
+ raise('expected a effective memberships user') unless user.class.try(:effective_memberships_user?)
159
+ where(user: user).or(where(organization: user.organizations))
160
+ }
158
161
 
159
- before_validation(if: -> { current_step == :select && category_id.present? }) do
160
- self.category_type ||= EffectiveMemberships.Category.name
162
+ # Set Apply to Join or Reclassification
163
+ before_validation(if: -> { (new_record? || current_step == :select) && owner.present? }) do
164
+ self.applicant_type = (owner.membership.blank? ? 'Apply to Join' : 'Apply to Reclassify')
165
+ self.from_category = owner.membership&.category
161
166
  end
162
167
 
163
168
  before_validation(if: -> { current_step == :experience }) do
@@ -165,18 +170,16 @@ module EffectiveMembershipsApplicant
165
170
  end
166
171
 
167
172
  # All Steps validations
168
- validates :owner, presence: true
173
+ validates :user, presence: true
169
174
  validates :from_category, presence: true, if: -> { reclassification? }
170
175
 
171
176
  validate(if: -> { reclassification? }) do
172
177
  errors.add(:category_id, "can't reclassify to existing category") if category_id == from_category_id
173
178
  end
174
179
 
175
- # Start Step
176
- with_options(if: -> { current_step == :start && owner.present? }) do
177
- validate do
178
- errors.add(:base, 'may not have outstanding fees') if owner.outstanding_fee_payment_fees.present?
179
- end
180
+ validate(if: -> { category.present? }) do
181
+ self.errors.add(:organization_id, "can't be blank when organization category") if category.organization? && organization.blank?
182
+ self.errors.add(:organization_id, "must be blank when individual category") if category.individual? && organization.present?
180
183
  end
181
184
 
182
185
  # Select Step
@@ -185,6 +188,10 @@ module EffectiveMembershipsApplicant
185
188
  validates :category, presence: true
186
189
  end
187
190
 
191
+ validate(if: -> { current_step == :select && owner.present? }) do
192
+ self.errors.add(:base, 'may not have outstanding fees') if owner.outstanding_fee_payment_fees.present?
193
+ end
194
+
188
195
  # Applicant Educations Step
189
196
  with_options(if: -> { current_step == :education }) do
190
197
  validate do
@@ -291,6 +298,14 @@ module EffectiveMembershipsApplicant
291
298
 
292
299
  # Special logic for stamp step
293
300
  applicant_steps.delete(:stamp) unless apply_to_join?
301
+ applicant_steps.delete(:organization) unless category&.organization?
302
+
303
+ # change_wizard_steps is defined in effective_resources acts_as_wizard
304
+ applicant_steps = change_wizard_steps(applicant_steps)
305
+
306
+ unless applicant_steps.kind_of?(Array) && applicant_steps.all? { |step| step.kind_of?(Symbol) }
307
+ raise('expected change_wizard_steps to return an Array of steps with no nils')
308
+ end
294
309
 
295
310
  wizard_steps.select do |step|
296
311
  required_steps.include?(step) || category.blank? || applicant_steps.include?(step)
@@ -370,6 +385,18 @@ module EffectiveMembershipsApplicant
370
385
  end
371
386
  end
372
387
 
388
+ def owner
389
+ organization || user
390
+ end
391
+
392
+ def owner_symbol
393
+ organization? ? :organization : :user
394
+ end
395
+
396
+ def build_organization(params = {})
397
+ self.organization = EffectiveMemberships.Organization.new(params)
398
+ end
399
+
373
400
  def apply_to_join?
374
401
  applicant_type == 'Apply to Join'
375
402
  end
@@ -378,8 +405,12 @@ module EffectiveMembershipsApplicant
378
405
  applicant_type == 'Apply to Reclassify'
379
406
  end
380
407
 
381
- def owner_label
382
- owner_type.to_s.split('::').last
408
+ def individual?
409
+ !(owner.kind_of?(EffectiveMemberships.Organization) && category&.organization?)
410
+ end
411
+
412
+ def organization?
413
+ owner.kind_of?(EffectiveMemberships.Organization) && category&.organization?
383
414
  end
384
415
 
385
416
  def in_progress?
@@ -399,9 +430,11 @@ module EffectiveMembershipsApplicant
399
430
  when 'draft'
400
431
  "Applicant has not yet completed the #{category} wizard steps or paid to submit this application. This application will transition to 'submitted' after payment has been collected."
401
432
  when 'submitted'
402
- summary = "Application has been purchased and submitted. The following tasks must be done before this application will transition to 'completed':"
433
+ summary = "Application has been purchased and submitted."
434
+ tasks = "The following tasks remain before it can be completed:"
435
+ approval = "Waiting on approval."
403
436
  items = completed_requirements.map { |item, done| "<li>#{item}: #{done ? 'Complete' : 'Incomplete'}</li>" }.join
404
- "<p>#{summary}</p><ul>#{items}</ul>"
437
+ completed_requirements.present? ? "<p>#{summary} #{tasks}</p><ul>#{items}</ul>" : "#{summary} #{approval}"
405
438
  when 'completed'
406
439
  if applicant_reviews_required?
407
440
  "All required materials have been provided. This application will transition to 'reviewed' after all reviewers have voted."
@@ -425,11 +458,11 @@ module EffectiveMembershipsApplicant
425
458
  def can_apply_categories_collection
426
459
  categories = EffectiveMemberships.Category.sorted.can_apply
427
460
 
428
- if owner.blank? || owner.membership.blank?
461
+ if user.blank? || !user.is?(:member)
429
462
  return categories.where(can_apply_new: true)
430
463
  end
431
464
 
432
- category_ids = owner.membership.category_ids
465
+ category_ids = user.memberships.map(&:category_ids).flatten
433
466
 
434
467
  categories.select do |cat|
435
468
  cat.can_apply_existing? ||
@@ -503,10 +536,6 @@ module EffectiveMembershipsApplicant
503
536
  )
504
537
  end
505
538
 
506
- # The submit! method used to be here
507
- # But it needs to be inside the included do block
508
- # So see above. Sorry.
509
-
510
539
  def applicant_references_required?
511
540
  min_applicant_references > 0
512
541
  end
@@ -514,9 +543,13 @@ module EffectiveMembershipsApplicant
514
543
  # When an application is submitted, these must be done to go to completed.
515
544
  # An Admin can override this and just set them to completed.
516
545
  def completed_requirements
517
- {
518
- 'Applicant References' => (!applicant_references_required? || applicant_references.count(&:completed?) >= min_applicant_references)
519
- }
546
+ if category&.applicant_wizard_steps&.include?(:references) || applicant_references_required?
547
+ {
548
+ 'Applicant References' => (!applicant_references_required? || applicant_references.count(&:completed?) >= min_applicant_references)
549
+ }
550
+ else
551
+ {}
552
+ end
520
553
  end
521
554
 
522
555
  def complete!
@@ -16,6 +16,10 @@ module EffectiveMembershipsCategory
16
16
  module ClassMethods
17
17
  def effective_memberships_category?; true; end
18
18
 
19
+ def category_types
20
+ ['Individual', 'Organization']
21
+ end
22
+
19
23
  def categories
20
24
  []
21
25
  end
@@ -35,6 +39,8 @@ module EffectiveMembershipsCategory
35
39
  has_many :membership_categories, class_name: 'Effective::MembershipCategory', as: :category
36
40
 
37
41
  effective_resource do
42
+ category_type :string
43
+
38
44
  title :string
39
45
  category :string
40
46
  position :integer
@@ -110,17 +116,18 @@ module EffectiveMembershipsCategory
110
116
  scope :create_bad_standing, -> { where(create_bad_standing: true) }
111
117
 
112
118
  validates :title, presence: true, uniqueness: true
113
-
119
+ validates :category_type, presence: true
114
120
  validates :position, presence: true
115
121
 
116
- after_initialize(if: -> { new_record? }) do
117
- self.applicant_wizard_steps = EffectiveMemberships.Applicant.all_wizard_steps
118
- self.applicant_review_wizard_steps = EffectiveMemberships.ApplicantReview.all_wizard_steps
119
- self.fee_payment_wizard_steps = EffectiveMemberships.FeePayment.all_wizard_steps
122
+ before_validation do
123
+ self.applicant_wizard_steps = EffectiveMemberships.Applicant.all_wizard_steps if applicant_wizard_steps.blank?
124
+ self.applicant_review_wizard_steps = EffectiveMemberships.ApplicantReview.all_wizard_steps if applicant_review_wizard_steps.blank?
125
+ self.fee_payment_wizard_steps = EffectiveMemberships.FeePayment.all_wizard_steps if fee_payment_wizard_steps.blank?
120
126
  end
121
127
 
122
128
  before_validation do
123
129
  self.position ||= (self.class.pluck(:position).compact.max || -1) + 1
130
+ self.category_type ||= self.class.category_types.first
124
131
  end
125
132
 
126
133
  with_options(if: -> { can_apply? }) do
@@ -155,6 +162,14 @@ module EffectiveMembershipsCategory
155
162
  can_apply_new? || can_apply_existing? || can_apply_restricted?
156
163
  end
157
164
 
165
+ def individual?
166
+ category_type == 'Individual'
167
+ end
168
+
169
+ def organization?
170
+ category_type == 'Organization'
171
+ end
172
+
158
173
  def prorated_fee(date:)
159
174
  send("prorated_#{date.strftime('%b').downcase}").to_i
160
175
  end
@@ -167,6 +182,18 @@ module EffectiveMembershipsCategory
167
182
  Array(self[:can_apply_restricted_ids]) - [nil, '']
168
183
  end
169
184
 
185
+ def optional_applicant_wizard_steps
186
+ applicant_wizard_steps - EffectiveMemberships.Applicant.required_wizard_steps
187
+ end
188
+
189
+ def optional_fee_payment_wizard_steps
190
+ fee_payment_wizard_steps - EffectiveMemberships.FeePayment.required_wizard_steps
191
+ end
192
+
193
+ def optional_applicant_review_wizard_steps
194
+ applicant_review_wizard_steps - EffectiveMemberships.ApplicantReview.required_wizard_steps
195
+ end
196
+
170
197
  def applicant_wizard_steps
171
198
  (Array(self[:applicant_wizard_steps]) - [nil, '']).map(&:to_sym)
172
199
  end
@@ -32,7 +32,8 @@ module EffectiveMembershipsFeePayment
32
32
 
33
33
  acts_as_wizard(
34
34
  start: 'Start',
35
- demographics: 'Demographics',
35
+ demographics: 'Demographics', # Individual only. Users fields.
36
+ organization: 'Organization', # Organization only. Organization fields.
36
37
  declarations: 'Declarations',
37
38
  summary: 'Review',
38
39
  billing: 'Billing Address',
@@ -48,23 +49,20 @@ module EffectiveMembershipsFeePayment
48
49
  attr_accessor :declare_code_of_ethics
49
50
  attr_accessor :declare_truth
50
51
 
51
- # Throwaway
52
- attr_accessor :upgrade, :downgrade
53
-
54
52
  # Application Namespace
55
- belongs_to :owner, polymorphic: true
56
- accepts_nested_attributes_for :owner
57
-
58
- belongs_to :user, polymorphic: true, optional: true
53
+ belongs_to :user, polymorphic: true
59
54
  accepts_nested_attributes_for :user
60
55
 
56
+ belongs_to :organization, polymorphic: true, optional: true
57
+ accepts_nested_attributes_for :organization
58
+
61
59
  # Like maybe optionally it makes sense.
62
60
  belongs_to :category, polymorphic: true, optional: true
63
61
 
62
+ # Effective Namespace
64
63
  has_many :fees, -> { order(:id) }, as: :parent, class_name: 'Effective::Fee', dependent: :nullify
65
64
  accepts_nested_attributes_for :fees, reject_if: :all_blank, allow_destroy: true
66
65
 
67
- # Effective Namespace
68
66
  has_many :orders, -> { order(:id) }, as: :parent, class_name: 'Effective::Order', dependent: :nullify
69
67
  accepts_nested_attributes_for :orders
70
68
 
@@ -83,24 +81,32 @@ module EffectiveMembershipsFeePayment
83
81
  timestamps
84
82
  end
85
83
 
86
- scope :deep, -> { includes(:owner, :category, :orders) }
84
+ scope :deep, -> { includes(:user, :organization, :category, :orders) }
87
85
  scope :sorted, -> { order(:id) }
88
86
 
89
87
  scope :in_progress, -> { where.not(status: [:submitted]) }
90
88
  scope :done, -> { where(status: [:submitted]) }
91
89
 
90
+ scope :for, -> (user) {
91
+ raise('expected a effective memberships user') unless user.class.try(:effective_memberships_user?)
92
+ where(user: user).or(where(organization: user.organizations))
93
+ }
94
+
92
95
  before_validation do
93
96
  self.period ||= EffectiveMemberships.Registrar.current_period
94
97
  end
95
98
 
96
- before_validation(if: -> { current_step == :start && owner && owner.membership }) do
97
- self.category ||= owner.membership.categories.first if owner.membership.categories.length == 1
99
+ before_validation(if: -> { new_record? || current_step == :start }) do
100
+ self.organization_type = (EffectiveMemberships.Organization.name if organization_id.present?)
98
101
  end
99
102
 
100
- validates :period, presence: true
103
+ before_validation(if: -> { current_step == :start && user && user.membership }) do
104
+ self.category ||= user.membership.categories.first if user.membership.categories.length == 1
105
+ end
101
106
 
102
107
  # All Steps validations
103
- validates :owner, presence: true
108
+ validates :user, presence: true
109
+ validates :period, presence: true
104
110
 
105
111
  # Declarations Step
106
112
  with_options(if: -> { current_step == :declarations }) do
@@ -121,6 +127,9 @@ module EffectiveMembershipsFeePayment
121
127
 
122
128
  fee_payment_steps = Array(category&.fee_payment_wizard_steps)
123
129
 
130
+ fee_payment_steps.delete(:organization) unless organization?
131
+
132
+
124
133
  wizard_steps.select do |step|
125
134
  required_steps.include?(step) || category.blank? || fee_payment_steps.include?(step)
126
135
  end
@@ -129,10 +138,6 @@ module EffectiveMembershipsFeePayment
129
138
 
130
139
  # All Fees and Orders
131
140
  # Overriding acts_as_purchasable_wizard
132
- def outstanding_fees
133
- owner&.outstanding_fee_payment_fees
134
- end
135
-
136
141
  def submit_fees
137
142
  fees
138
143
  end
@@ -143,7 +148,7 @@ module EffectiveMembershipsFeePayment
143
148
 
144
149
  # We take over the owner's outstanding fees.
145
150
  def find_or_build_submit_fees
146
- Array(outstanding_fees).each { |fee| fees << fee unless fees.include?(fee) }
151
+ Array(owner.outstanding_fee_payment_fees).each { |fee| fees << fee unless fees.include?(fee) }
147
152
  submit_fees
148
153
  end
149
154
 
@@ -157,6 +162,26 @@ module EffectiveMembershipsFeePayment
157
162
  'Fee Payment'
158
163
  end
159
164
 
165
+ def owner
166
+ organization || user
167
+ end
168
+
169
+ def owner_symbol
170
+ organization? ? :organization : :user
171
+ end
172
+
173
+ def build_organization(params = {})
174
+ self.organization = EffectiveMemberships.Organization.new(params)
175
+ end
176
+
177
+ def individual?
178
+ !owner.kind_of?(EffectiveMemberships.Organization)
179
+ end
180
+
181
+ def organization?
182
+ owner.kind_of?(EffectiveMemberships.Organization)
183
+ end
184
+
160
185
  # Instance Methods
161
186
  def in_progress?
162
187
  draft?
@@ -175,30 +200,4 @@ module EffectiveMembershipsFeePayment
175
200
  save!
176
201
  end
177
202
 
178
- # Work with effective_organizations
179
- def organization!
180
- if upgrade_individual_to_organization?
181
- save!
182
- update!(owner: owner.representatives.first.organization)
183
- elsif downgrade_organization_to_individual?
184
- save!
185
- update!(owner: current_user)
186
- else
187
- save!
188
- end
189
- end
190
-
191
- def upgrade_individual_to_organization?
192
- return false unless EffectiveResources.truthy?(upgrade)
193
- return false unless owner.class.respond_to?(:effective_organizations_user?)
194
- owner.representatives.any?(&:new_record?)
195
- end
196
-
197
- def downgrade_organization_to_individual?
198
- return false unless EffectiveResources.truthy?(downgrade)
199
- return false unless owner.class.respond_to?(:effective_organizations_organization?)
200
- return false if current_user.blank?
201
- owner.representatives.any?(&:marked_for_destruction?)
202
- end
203
-
204
203
  end
@@ -0,0 +1,94 @@
1
+ # EffectiveMembershipsOrganization
2
+ #
3
+ # Mark your category model with effective_memberships_organization to get all the includes
4
+
5
+ module EffectiveMembershipsOrganization
6
+ extend ActiveSupport::Concern
7
+
8
+ module Base
9
+ def effective_memberships_organization
10
+ include ::EffectiveMembershipsOrganization
11
+ end
12
+ end
13
+
14
+ module ClassMethods
15
+ def effective_memberships_organization?; true; end
16
+
17
+ def categories
18
+ []
19
+ end
20
+ end
21
+
22
+ included do
23
+ effective_memberships_owner
24
+
25
+ acts_as_addressable :billing # effective_addresses
26
+ log_changes(except: [:representatives, :users]) if respond_to?(:log_changes)
27
+
28
+ # rich_text_body
29
+ # has_many_rich_texts
30
+
31
+ # App scoped
32
+ has_many :applicants, -> { order(:id) }, inverse_of: :organization, as: :organization
33
+ has_many :fee_payments, -> { order(:id) }, inverse_of: :organization, as: :organization
34
+
35
+ # Effective scoped
36
+ has_many :representatives, -> { Effective::Representative.sorted },
37
+ class_name: 'Effective::Representative', inverse_of: :organization, dependent: :delete_all
38
+
39
+ accepts_nested_attributes_for :representatives, allow_destroy: true
40
+
41
+ effective_resource do
42
+ title :string
43
+ email :string
44
+
45
+ phone :string
46
+ fax :string
47
+ website :string
48
+
49
+ category :string
50
+
51
+ notes :text
52
+
53
+ roles_mask :integer
54
+ archived :boolean
55
+
56
+ representatives_count :integer # Counter cache
57
+
58
+ timestamps
59
+ end
60
+
61
+ scope :deep, -> { includes(:representatives) }
62
+ scope :sorted, -> { order(:title) }
63
+
64
+ validates :title, presence: true, uniqueness: true
65
+ validates :email, presence: true
66
+ end
67
+
68
+ # Instance Methods
69
+ def to_s
70
+ title.presence || 'organization'
71
+ end
72
+
73
+ def membership_present?
74
+ membership.present? && !membership.marked_for_destruction?
75
+ end
76
+
77
+ def outstanding_fee_payment_fees
78
+ fees.select { |fee| fee.fee_payment_fee? && !fee.purchased? }
79
+ end
80
+
81
+ def representative(user:)
82
+ representatives.find { |rep| rep.user_id == user.id }
83
+ end
84
+
85
+ # Find or build
86
+ def build_representative(user:)
87
+ representative(user: user) || representatives.build(user: user)
88
+ end
89
+
90
+ def users
91
+ representatives.reject(&:marked_for_destruction?).map(&:user)
92
+ end
93
+
94
+ end
@@ -23,10 +23,6 @@ module EffectiveMembershipsOwner
23
23
  included do
24
24
  acts_as_role_restricted unless respond_to?(:acts_as_role_restricted?)
25
25
 
26
- # App scoped
27
- has_many :applicants, -> { order(:id) }, inverse_of: :owner, as: :owner
28
- has_many :fee_payments, -> { order(:id) }, inverse_of: :owner, as: :owner
29
-
30
26
  # Effective scoped
31
27
  has_many :fees, -> { order(:id) }, inverse_of: :owner, as: :owner, class_name: 'Effective::Fee', dependent: :nullify
32
28
  accepts_nested_attributes_for :fees, reject_if: :all_blank, allow_destroy: true
@@ -40,48 +36,9 @@ module EffectiveMembershipsOwner
40
36
  has_many :membership_histories, -> { Effective::MembershipHistory.sorted }, inverse_of: :owner, as: :owner, class_name: 'Effective::MembershipHistory'
41
37
  accepts_nested_attributes_for :membership_histories
42
38
 
43
- effective_resource do
44
- timestamps
45
- end
46
-
47
39
  scope :members, -> { joins(:membership) }
48
40
  end
49
41
 
50
- def effective_memberships_owner
51
- raise('expected singular usage but there are more than one owner') if effective_memberships_owners.length > 1
52
- effective_memberships_owners.first
53
- end
54
-
55
- def effective_memberships_owners
56
- owners = organizations if self.class.respond_to?(:effective_organizations_user?)
57
- owners = users if self.class.respond_to?(:effective_organizations_organization?)
58
-
59
- owners = Array(owners)
60
- .select { |owner| owner.class.respond_to?(:effective_memberships_owner?) }
61
- .reject { |owner| owner.try(:archived?) }
62
-
63
- owners.presence || [self]
64
- end
65
-
66
- # This is the calculated way of determining if an owner is a member or not.
67
- # The correct way to check for membership is: current_user.is?(:member)
68
- def membership_present?
69
- individual_membership_present? || organization_membership_present?
70
- end
71
-
72
- def individual_membership_present?
73
- membership.present? && !membership.marked_for_destruction?
74
- end
75
-
76
- def organization_membership_present?(except: nil)
77
- return false unless self.class.respond_to?(:effective_organizations_user?)
78
-
79
- organizations
80
- .select { |organization| organization.class.respond_to?(:effective_memberships_owner?) }
81
- .reject { |organization| organization.try(:archived?) }
82
- .any? { |organization| organization != except && organization.membership_present? }
83
- end
84
-
85
42
  def assign_member_role
86
43
  membership_present? ? add_role(:member) : remove_role(:member)
87
44
  end
@@ -92,18 +49,6 @@ module EffectiveMembershipsOwner
92
49
  save!
93
50
  end
94
51
 
95
- def outstanding_fee_payment_owners
96
- effective_memberships_owners.select { |owner| !owner.membership_fees_paid? }
97
- end
98
-
99
- def current_fee_payment_owner
100
- outstanding_fee_payment_owners.first || self
101
- end
102
-
103
- def owner_label
104
- self.class.name.split('::').last
105
- end
106
-
107
52
  def membership_fees_paid?
108
53
  outstanding_fee_payment_fees.blank? && membership && membership.fees_paid?
109
54
  end
@@ -207,9 +207,10 @@ module EffectiveMembershipsRegistrar
207
207
  save!(owner, date: date)
208
208
  end
209
209
 
210
- def fees_paid!(owner, date: nil)
210
+ def fees_paid!(owner, date: nil, order_attributes: nil)
211
211
  raise('expecting a memberships owner') unless owner.class.respond_to?(:effective_memberships_owner?)
212
212
  raise('expected a member') unless owner.membership.present?
213
+ raise('expected a Hash of attributes') if order_attributes.present? && !order_attributes.kind_of?(Hash)
213
214
 
214
215
  # Date
215
216
  date ||= Time.zone.now
@@ -219,6 +220,7 @@ module EffectiveMembershipsRegistrar
219
220
 
220
221
  if owner.outstanding_fee_payment_fees.present?
221
222
  order = Effective::Order.new(items: owner.outstanding_fee_payment_fees, user: owner)
223
+ order.assign_attributes(order_attributes) if order_attributes.present?
222
224
  order.mark_as_purchased!
223
225
  end
224
226
 
@@ -305,7 +307,7 @@ module EffectiveMembershipsRegistrar
305
307
  def add_member_role(owner)
306
308
  owner.add_role(:member)
307
309
 
308
- if owner.class.respond_to?(:effective_organizations_organization?)
310
+ if owner.class.respond_to?(:effective_memberships_organization?)
309
311
  organization = owner
310
312
  organization.representatives.each { |representative| representative.user.add_role(:member) }
311
313
  end
@@ -316,7 +318,7 @@ module EffectiveMembershipsRegistrar
316
318
  def remove_member_role(owner)
317
319
  owner.remove_role(:member)
318
320
 
319
- if owner.class.respond_to?(:effective_organizations_organization?)
321
+ if owner.class.respond_to?(:effective_memberships_organization?)
320
322
  organization = owner
321
323
 
322
324
  organization.representatives.each do |representative|