effective_memberships 0.3.14 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/admin/organizations_controller.rb +19 -0
- data/app/controllers/admin/representatives_controller.rb +19 -0
- data/app/controllers/effective/applicants_controller.rb +2 -3
- data/app/controllers/effective/fee_payments_controller.rb +1 -2
- data/app/controllers/effective/organizations_controller.rb +16 -0
- data/app/controllers/effective/representatives_controller.rb +19 -0
- data/app/datatables/admin/effective_applicants_datatable.rb +10 -5
- data/app/datatables/admin/effective_categories_datatable.rb +7 -0
- data/app/datatables/admin/effective_fee_payments_datatable.rb +11 -6
- data/app/datatables/admin/effective_organizations_datatable.rb +31 -0
- data/app/datatables/admin/effective_representatives_datatable.rb +28 -0
- data/app/datatables/effective_applicants_datatable.rb +1 -1
- data/app/datatables/effective_fee_payments_datatable.rb +5 -4
- data/app/datatables/effective_organizations_datatable.rb +18 -0
- data/app/datatables/effective_representatives_datatable.rb +40 -0
- data/app/helpers/effective_memberships_helper.rb +25 -0
- data/app/mailers/effective/memberships_mailer.rb +7 -7
- data/app/models/concerns/effective_memberships_applicant.rb +63 -30
- data/app/models/concerns/effective_memberships_category.rb +32 -5
- data/app/models/concerns/effective_memberships_fee_payment.rb +44 -45
- data/app/models/concerns/effective_memberships_organization.rb +94 -0
- data/app/models/concerns/effective_memberships_owner.rb +0 -55
- data/app/models/concerns/effective_memberships_registrar.rb +2 -2
- data/app/models/concerns/effective_memberships_user.rb +70 -0
- data/app/models/effective/fee.rb +1 -1
- data/app/models/effective/organization.rb +8 -0
- data/app/models/effective/representative.rb +56 -0
- data/app/views/admin/categories/_form_applicant_eligibility.html.haml +1 -1
- data/app/views/admin/categories/_form_applicant_steps.html.haml +29 -24
- data/app/views/admin/categories/_form_category.html.haml +3 -0
- data/app/views/admin/categories/_form_renewals.html.haml +0 -2
- data/app/views/admin/organizations/_fields.html.haml +6 -0
- data/app/views/admin/organizations/_form.html.haml +31 -0
- data/app/views/admin/organizations/_form_organization.html.haml +23 -0
- data/app/views/admin/representatives/_form.html.haml +38 -0
- data/app/views/{effective/applicants/_demographics_fields.html.haml → admin/representatives/_user_fields.html.haml} +2 -6
- data/app/views/effective/applicants/_dashboard.html.haml +24 -5
- data/app/views/effective/applicants/_demographics.html.haml +1 -1
- data/app/views/effective/applicants/_missing_info.html.haml +7 -3
- data/app/views/effective/applicants/_organization.html.haml +9 -0
- data/app/views/effective/applicants/_select_organization.html.haml +21 -0
- data/app/views/effective/applicants/_summary.html.haml +17 -9
- data/app/views/effective/applicants/billing.html.haml +2 -2
- data/app/views/effective/applicants/demographics.html.haml +7 -6
- data/app/views/effective/applicants/education.html.haml +2 -2
- data/app/views/effective/applicants/organization.html.haml +19 -0
- data/app/views/effective/applicants/references.html.haml +1 -1
- data/app/views/effective/applicants/select.html.haml +11 -1
- data/app/views/effective/applicants/stamp.html.haml +2 -2
- data/app/views/effective/applicants/start.html.haml +17 -11
- data/app/views/effective/applicants/submitted.html.haml +5 -5
- data/app/views/effective/applicants/summary.html.haml +1 -1
- data/app/views/effective/fee_payments/_demographics.html.haml +1 -1
- data/app/views/effective/fee_payments/_organization.html.haml +9 -0
- data/app/views/effective/fee_payments/_summary.html.haml +39 -1
- data/app/views/effective/fee_payments/billing.html.haml +2 -2
- data/app/views/effective/fee_payments/demographics.html.haml +2 -2
- data/app/views/effective/fee_payments/organization.html.haml +18 -0
- data/app/views/effective/fee_payments/start.html.haml +20 -17
- data/app/views/effective/fee_payments/submitted.html.haml +10 -3
- data/app/views/effective/fees/_dashboard.html.haml +20 -8
- data/app/views/effective/memberships/_dashboard.html.haml +16 -5
- data/app/views/effective/organizations/_dashboard.html.haml +10 -0
- data/app/views/effective/organizations/_form.html.haml +8 -0
- data/app/views/effective/organizations/_form_organization.html.haml +11 -0
- data/app/views/effective/representatives/_form.html.haml +33 -0
- data/app/views/effective/{fee_payments/_demographics_fields.html.haml → representatives/_user_fields.html.haml} +2 -6
- data/app/views/organizations/_demographics.html.haml +45 -0
- data/app/views/organizations/_fields_demographics.html.haml +29 -0
- data/app/views/users/_demographics.html.haml +50 -0
- data/app/views/users/_fields_demographics.html.haml +29 -0
- data/config/effective_memberships.rb +3 -0
- data/config/routes.rb +9 -0
- data/db/migrate/01_create_effective_memberships.rb.erb +57 -10
- data/db/seeds.rb +18 -0
- data/lib/effective_memberships/engine.rb +3 -0
- data/lib/effective_memberships/version.rb +1 -1
- data/lib/effective_memberships.rb +6 -2
- metadata +33 -20
- data/app/views/effective/applicants/_demographics_owner.html.haml +0 -20
- data/app/views/effective/fee_payments/_demographics_owner.html.haml +0 -20
@@ -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
|
-
|
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 :
|
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(:
|
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
|
97
|
-
self.
|
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
|
-
|
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 :
|
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(
|
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
|
@@ -305,7 +305,7 @@ module EffectiveMembershipsRegistrar
|
|
305
305
|
def add_member_role(owner)
|
306
306
|
owner.add_role(:member)
|
307
307
|
|
308
|
-
if owner.class.respond_to?(:
|
308
|
+
if owner.class.respond_to?(:effective_memberships_organization?)
|
309
309
|
organization = owner
|
310
310
|
organization.representatives.each { |representative| representative.user.add_role(:member) }
|
311
311
|
end
|
@@ -316,7 +316,7 @@ module EffectiveMembershipsRegistrar
|
|
316
316
|
def remove_member_role(owner)
|
317
317
|
owner.remove_role(:member)
|
318
318
|
|
319
|
-
if owner.class.respond_to?(:
|
319
|
+
if owner.class.respond_to?(:effective_memberships_organization?)
|
320
320
|
organization = owner
|
321
321
|
|
322
322
|
organization.representatives.each do |representative|
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# EffectiveMembershipsUser
|
2
|
+
#
|
3
|
+
# Mark your user model with effective_memberships_user to get all the includes
|
4
|
+
|
5
|
+
module EffectiveMembershipsUser
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
module Base
|
9
|
+
def effective_memberships_user
|
10
|
+
include ::EffectiveMembershipsUser
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
def effective_memberships_user?; true; end
|
16
|
+
end
|
17
|
+
|
18
|
+
included do
|
19
|
+
effective_memberships_owner
|
20
|
+
|
21
|
+
# App scoped
|
22
|
+
has_many :applicants, -> { order(:id) }, inverse_of: :user, as: :user
|
23
|
+
has_many :fee_payments, -> { order(:id) }, inverse_of: :user, as: :user
|
24
|
+
|
25
|
+
# Effective Scoped
|
26
|
+
has_many :representatives, -> { Effective::Representative.sorted },
|
27
|
+
class_name: 'Effective::Representative', inverse_of: :user, dependent: :delete_all
|
28
|
+
|
29
|
+
accepts_nested_attributes_for :representatives, allow_destroy: true
|
30
|
+
end
|
31
|
+
|
32
|
+
# Instance Methods
|
33
|
+
def memberships
|
34
|
+
Array(membership) + membership_organizations.map(&:membership)
|
35
|
+
end
|
36
|
+
|
37
|
+
def memberships_owners
|
38
|
+
Array(is?(:member) ? self : nil) + membership_organizations
|
39
|
+
end
|
40
|
+
|
41
|
+
def membership_present?
|
42
|
+
individual_membership_present? || organization_membership_present?
|
43
|
+
end
|
44
|
+
|
45
|
+
def individual_membership_present?
|
46
|
+
membership.present? && !membership.marked_for_destruction?
|
47
|
+
end
|
48
|
+
|
49
|
+
def organization_membership_present?(except: nil)
|
50
|
+
organizations.reject(&:archived?).any? { |organization| organization != except && organization.membership_present? }
|
51
|
+
end
|
52
|
+
|
53
|
+
def representative(organization:)
|
54
|
+
representatives.find { |rep| rep.organization_id == organization.id } if organization
|
55
|
+
end
|
56
|
+
|
57
|
+
# Find or build
|
58
|
+
def build_representative(organization:)
|
59
|
+
representative(organization: organization) || representatives.build(organization: organization)
|
60
|
+
end
|
61
|
+
|
62
|
+
def organizations
|
63
|
+
representatives.reject(&:marked_for_destruction?).map(&:organization)
|
64
|
+
end
|
65
|
+
|
66
|
+
def membership_organizations
|
67
|
+
organizations.select { |organization| organization.is?(:member) && !organization.archived? }
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
data/app/models/effective/fee.rb
CHANGED
@@ -4,7 +4,7 @@ module Effective
|
|
4
4
|
|
5
5
|
log_changes(to: :owner) if respond_to?(:log_changes)
|
6
6
|
|
7
|
-
# Every fee is charged to a owner
|
7
|
+
# Every fee is charged to a owner: a user or an organization
|
8
8
|
belongs_to :owner, polymorphic: true
|
9
9
|
|
10
10
|
# This fee may belong to an application, fee payment, or other parent model
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Effective
|
4
|
+
class Representative < ActiveRecord::Base
|
5
|
+
attr_accessor :new_representative_user_action
|
6
|
+
|
7
|
+
acts_as_role_restricted
|
8
|
+
|
9
|
+
log_changes(to: :organization) if respond_to?(:log_changes)
|
10
|
+
|
11
|
+
belongs_to :organization, polymorphic: true, counter_cache: true
|
12
|
+
belongs_to :user, polymorphic: true
|
13
|
+
|
14
|
+
accepts_nested_attributes_for :organization
|
15
|
+
accepts_nested_attributes_for :user
|
16
|
+
|
17
|
+
effective_resource do
|
18
|
+
roles_mask :integer
|
19
|
+
|
20
|
+
timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
scope :sorted, -> { order(:id) }
|
24
|
+
scope :deep, -> { includes(:user, :organization) }
|
25
|
+
|
26
|
+
before_validation(if: -> { user && user.new_record? }) do
|
27
|
+
user.password ||= SecureRandom.base64(12) + '!@#123abcABC-'
|
28
|
+
end
|
29
|
+
|
30
|
+
after_commit(on: [:create, :destroy], if: -> { user.class.respond_to?(:effective_memberships_owner?) }) do
|
31
|
+
user.representatives.reload
|
32
|
+
user.update_member_role!
|
33
|
+
end
|
34
|
+
|
35
|
+
validates :organization, presence: true
|
36
|
+
validates :user, presence: true
|
37
|
+
|
38
|
+
validates :user_id, if: -> { user_id && user_type && organization_id && organization_type },
|
39
|
+
uniqueness: { scope: [:organization_id, :organization_type], message: 'already belongs to this organization' }
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
user.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_user(attributes = {})
|
46
|
+
raise('please assign user_type first') if user_type.blank?
|
47
|
+
self.user = user_type.constantize.new(attributes)
|
48
|
+
end
|
49
|
+
|
50
|
+
def build_organization(attributes = {})
|
51
|
+
raise('please assign organization_type first') if organization_type.blank?
|
52
|
+
self.organization = organization_type.constantize.new(attributes)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
%h3 Eligibility
|
3
3
|
%p Please configure who may apply for this membership category.
|
4
4
|
|
5
|
-
= f.check_box :can_apply_new, label: 'Yes, new
|
5
|
+
= f.check_box :can_apply_new, label: 'Yes, new applicants may apply to join'
|
6
6
|
= f.check_box :can_apply_existing, label: 'Yes, existing members of any category may apply to join'
|
7
7
|
= f.check_box :can_apply_restricted, label: 'Only existing members of the following categories may apply to join'
|
8
8
|
|
@@ -14,29 +14,34 @@
|
|
14
14
|
|
15
15
|
%table.table.table-sm
|
16
16
|
%tbody
|
17
|
-
|
18
|
-
%
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
%
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
%
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
17
|
+
- if applicant.wizard_step_keys.include?(:education)
|
18
|
+
%tr
|
19
|
+
%td= applicant.wizard_step_title(:education)
|
20
|
+
%td= f.number_field :min_applicant_educations, label: false
|
21
|
+
%td minimum number of degrees
|
22
|
+
|
23
|
+
- if applicant.wizard_step_keys.include?(:course_amounts)
|
24
|
+
%tr
|
25
|
+
%td= applicant.wizard_step_title(:course_amounts)
|
26
|
+
%td= f.number_field :min_applicant_courses, label: false
|
27
|
+
%td minimum number of courses
|
28
|
+
|
29
|
+
- if applicant.wizard_step_keys.include?(:experience)
|
30
|
+
%tr
|
31
|
+
%td= applicant.wizard_step_title(:experience)
|
32
|
+
%td= f.number_field :min_applicant_experiences_months, label: false
|
33
|
+
%td minimimum months of work experience
|
34
|
+
|
35
|
+
- if applicant.wizard_step_keys.include?(:references)
|
36
|
+
%tr
|
37
|
+
%td= applicant.wizard_step_title(:references)
|
38
|
+
%td= f.number_field :min_applicant_references, label: false
|
39
|
+
%td minimimum number of references
|
40
|
+
|
41
|
+
- if applicant.wizard_step_keys.include?(:files)
|
42
|
+
%tr
|
43
|
+
%td= applicant.wizard_step_title(:files)
|
44
|
+
%td= f.number_field :min_applicant_files, label: false
|
45
|
+
%td minimimum number of attached files
|
41
46
|
|
42
47
|
= f.submit
|
@@ -1,6 +1,9 @@
|
|
1
1
|
= effective_form_with(model: [:admin, category], engine: true) do |f|
|
2
2
|
= f.text_field :title
|
3
3
|
|
4
|
+
= f.select :category_type, f.object.class.category_types,
|
5
|
+
hint: 'When Organization, the organization will be given membership. Otherwise the individual user'
|
6
|
+
|
4
7
|
- if f.object.class.categories.present?
|
5
8
|
= f.select :category, f.object.class.categories
|
6
9
|
|