effective_memberships 0.1.2
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +114 -0
- data/Rakefile +18 -0
- data/app/assets/config/effective_memberships_manifest.js +3 -0
- data/app/assets/javascripts/effective_memberships/applicant_courses.js +29 -0
- data/app/assets/javascripts/effective_memberships/applicant_experiences.js +38 -0
- data/app/assets/javascripts/effective_memberships/base.js +0 -0
- data/app/assets/javascripts/effective_memberships.js +1 -0
- data/app/assets/stylesheets/effective_memberships/base.scss +5 -0
- data/app/assets/stylesheets/effective_memberships.scss +1 -0
- data/app/controllers/admin/applicant_course_areas_controller.rb +15 -0
- data/app/controllers/admin/applicant_course_names_controller.rb +15 -0
- data/app/controllers/admin/applicants_controller.rb +33 -0
- data/app/controllers/admin/categories_controller.rb +19 -0
- data/app/controllers/admin/fees_controller.rb +18 -0
- data/app/controllers/admin/registrar_actions_controller.rb +49 -0
- data/app/controllers/effective/applicant_references_controller.rb +37 -0
- data/app/controllers/effective/applicants_controller.rb +34 -0
- data/app/controllers/effective/fee_payments_controller.rb +29 -0
- data/app/datatables/admin/effective_applicant_course_areas_datatable.rb +17 -0
- data/app/datatables/admin/effective_applicant_course_names_datatable.rb +17 -0
- data/app/datatables/admin/effective_applicants_datatable.rb +55 -0
- data/app/datatables/admin/effective_categories_datatable.rb +23 -0
- data/app/datatables/admin/effective_fees_datatable.rb +69 -0
- data/app/datatables/admin/effective_membership_histories_datatable.rb +35 -0
- data/app/datatables/effective_applicant_courses_datatable.rb +30 -0
- data/app/datatables/effective_applicant_educations_datatable.rb +22 -0
- data/app/datatables/effective_applicant_experiences_datatable.rb +42 -0
- data/app/datatables/effective_applicant_references_datatable.rb +34 -0
- data/app/datatables/effective_applicants_datatable.rb +34 -0
- data/app/helpers/effective_memberships_helper.rb +15 -0
- data/app/mailers/effective/memberships_mailer.rb +84 -0
- data/app/models/concerns/effective_memberships_applicant.rb +612 -0
- data/app/models/concerns/effective_memberships_applicant_review.rb +149 -0
- data/app/models/concerns/effective_memberships_category.rb +196 -0
- data/app/models/concerns/effective_memberships_fee_payment.rb +229 -0
- data/app/models/concerns/effective_memberships_owner.rb +263 -0
- data/app/models/concerns/effective_memberships_registrar.rb +300 -0
- data/app/models/effective/applicant.rb +7 -0
- data/app/models/effective/applicant_course.rb +40 -0
- data/app/models/effective/applicant_course_area.rb +31 -0
- data/app/models/effective/applicant_course_name.rb +29 -0
- data/app/models/effective/applicant_education.rb +36 -0
- data/app/models/effective/applicant_experience.rb +79 -0
- data/app/models/effective/applicant_reference.rb +81 -0
- data/app/models/effective/applicant_review.rb +7 -0
- data/app/models/effective/category.rb +7 -0
- data/app/models/effective/fee.rb +142 -0
- data/app/models/effective/fee_payment.rb +7 -0
- data/app/models/effective/membership.rb +119 -0
- data/app/models/effective/membership_category.rb +11 -0
- data/app/models/effective/membership_history.rb +40 -0
- data/app/models/effective/registrar.rb +19 -0
- data/app/models/effective/registrar_action.rb +97 -0
- data/app/views/admin/applicant_course_areas/_form.html.haml +8 -0
- data/app/views/admin/applicant_course_areas/_form_applicant_course_area.html.haml +8 -0
- data/app/views/admin/applicant_course_areas/index.html.haml +8 -0
- data/app/views/admin/applicant_course_name/_form.html.haml +9 -0
- data/app/views/admin/applicants/_form.html.haml +38 -0
- data/app/views/admin/applicants/_form_approve.html.haml +34 -0
- data/app/views/admin/applicants/_form_decline.html.haml +11 -0
- data/app/views/admin/applicants/_form_process.html.haml +18 -0
- data/app/views/admin/applicants/_status.html.haml +133 -0
- data/app/views/admin/categories/_form.html.haml +14 -0
- data/app/views/admin/categories/_form_applicant.html.haml +12 -0
- data/app/views/admin/categories/_form_applicant_content.html.haml +19 -0
- data/app/views/admin/categories/_form_applicant_eligibility.html.haml +13 -0
- data/app/views/admin/categories/_form_applicant_fees.html.haml +29 -0
- data/app/views/admin/categories/_form_applicant_steps.html.haml +42 -0
- data/app/views/admin/categories/_form_category.html.haml +10 -0
- data/app/views/admin/categories/_form_fee_payment.html.haml +9 -0
- data/app/views/admin/categories/_form_fee_payment_content.html.haml +19 -0
- data/app/views/admin/categories/_form_fee_payment_steps.html.haml +9 -0
- data/app/views/admin/categories/_form_renewals.html.haml +32 -0
- data/app/views/admin/fees/_fee.html.haml +1 -0
- data/app/views/admin/fees/_form.html.haml +14 -0
- data/app/views/admin/memberships/_status.html.haml +6 -0
- data/app/views/admin/registrar_actions/_form.html.haml +10 -0
- data/app/views/admin/registrar_actions/_form_bad_standing.html.haml +43 -0
- data/app/views/admin/registrar_actions/_form_fees_paid.html.haml +30 -0
- data/app/views/admin/registrar_actions/_form_reclassify.html.haml +43 -0
- data/app/views/admin/registrar_actions/_form_register.html.haml +44 -0
- data/app/views/admin/registrar_actions/_form_remove.html.haml +17 -0
- data/app/views/effective/applicant_references/_applicant_reference.html.haml +51 -0
- data/app/views/effective/applicant_references/_datatable_actions.html.haml +4 -0
- data/app/views/effective/applicant_references/_form.html.haml +18 -0
- data/app/views/effective/applicant_references/_form_declaration.html.haml +37 -0
- data/app/views/effective/applicant_references/complete.html.haml +3 -0
- data/app/views/effective/applicant_references/edit.html.haml +8 -0
- data/app/views/effective/applicants/_applicant.html.haml +6 -0
- data/app/views/effective/applicants/_content.html.haml +10 -0
- data/app/views/effective/applicants/_course_amounts.html.haml +19 -0
- data/app/views/effective/applicants/_dashboard.html.haml +19 -0
- data/app/views/effective/applicants/_declarations.html.haml +16 -0
- data/app/views/effective/applicants/_demographics.html.haml +9 -0
- data/app/views/effective/applicants/_demographics_fields.html.haml +11 -0
- data/app/views/effective/applicants/_demographics_owner.html.haml +20 -0
- data/app/views/effective/applicants/_education.html.haml +14 -0
- data/app/views/effective/applicants/_experience.html.haml +28 -0
- data/app/views/effective/applicants/_files.html.haml +27 -0
- data/app/views/effective/applicants/_layout.html.haml +3 -0
- data/app/views/effective/applicants/_orders.html.haml +4 -0
- data/app/views/effective/applicants/_references.html.haml +15 -0
- data/app/views/effective/applicants/_summary.html.haml +40 -0
- data/app/views/effective/applicants/billing.html.haml +14 -0
- data/app/views/effective/applicants/checkout.html.haml +6 -0
- data/app/views/effective/applicants/course_amounts.html.haml +50 -0
- data/app/views/effective/applicants/declarations.html.haml +19 -0
- data/app/views/effective/applicants/demographics.html.haml +11 -0
- data/app/views/effective/applicants/education.html.haml +27 -0
- data/app/views/effective/applicants/experience.html.haml +51 -0
- data/app/views/effective/applicants/files.html.haml +14 -0
- data/app/views/effective/applicants/references.html.haml +24 -0
- data/app/views/effective/applicants/select.html.haml +27 -0
- data/app/views/effective/applicants/start.html.haml +18 -0
- data/app/views/effective/applicants/submitted.html.haml +44 -0
- data/app/views/effective/applicants/summary.html.haml +8 -0
- data/app/views/effective/fee_payments/_content.html.haml +8 -0
- data/app/views/effective/fee_payments/_declarations.html.haml +16 -0
- data/app/views/effective/fee_payments/_demographics.html.haml +9 -0
- data/app/views/effective/fee_payments/_demographics_fields.html.haml +11 -0
- data/app/views/effective/fee_payments/_demographics_owner.html.haml +20 -0
- data/app/views/effective/fee_payments/_fee_payment.html.haml +6 -0
- data/app/views/effective/fee_payments/_layout.html.haml +3 -0
- data/app/views/effective/fee_payments/_orders.html.haml +4 -0
- data/app/views/effective/fee_payments/billing.html.haml +14 -0
- data/app/views/effective/fee_payments/checkout.html.haml +6 -0
- data/app/views/effective/fee_payments/declarations.html.haml +20 -0
- data/app/views/effective/fee_payments/demographics.html.haml +12 -0
- data/app/views/effective/fee_payments/start.html.haml +20 -0
- data/app/views/effective/fee_payments/submitted.html.haml +14 -0
- data/app/views/effective/fee_payments/summary.html.haml +8 -0
- data/app/views/effective/fees/_dashboard.html.haml +22 -0
- data/app/views/effective/fees/_fee.html.haml +37 -0
- data/app/views/effective/memberships/_dashboard.html.haml +29 -0
- data/app/views/effective/memberships/_membership.html.haml +40 -0
- data/app/views/effective/memberships_mailer/applicant_approved.liquid +15 -0
- data/app/views/effective/memberships_mailer/applicant_declined.liquid +13 -0
- data/app/views/effective/memberships_mailer/applicant_reference_notification.liquid +15 -0
- data/app/views/layouts/effective_memberships_mailer_layout.html.haml +7 -0
- data/config/effective_memberships.rb +47 -0
- data/config/routes.rb +32 -0
- data/db/migrate/01_create_effective_memberships.rb.erb +380 -0
- data/db/seeds.rb +59 -0
- data/lib/effective_memberships/engine.rb +23 -0
- data/lib/effective_memberships/version.rb +3 -0
- data/lib/effective_memberships.rb +86 -0
- data/lib/generators/effective_memberships/install_generator.rb +40 -0
- data/lib/generators/templates/effective_memberships_mailer_preview.rb +4 -0
- data/lib/tasks/effective_memberships_tasks.rake +17 -0
- metadata +377 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# EffectiveMembershipsApplicantReview
|
|
4
|
+
#
|
|
5
|
+
# Mark your category model with effective_memberships_applicant_review to get all the includes
|
|
6
|
+
|
|
7
|
+
module EffectiveMembershipsApplicantReview
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
module Base
|
|
11
|
+
def effective_memberships_applicant_review
|
|
12
|
+
include ::EffectiveMembershipsApplicantReview
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module ClassMethods
|
|
17
|
+
def effective_memberships_applicant_review?; true; end
|
|
18
|
+
|
|
19
|
+
def all_wizard_steps
|
|
20
|
+
const_get(:WIZARD_STEPS).keys
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# For effective_category_applicant_wizard_steps_collection
|
|
24
|
+
def required_wizard_steps
|
|
25
|
+
[:start, :recommendation, :submitted]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def recommendations
|
|
29
|
+
['Accept', 'Reject']
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
included do
|
|
35
|
+
log_changes if respond_to?(:log_changes)
|
|
36
|
+
|
|
37
|
+
acts_as_tokened
|
|
38
|
+
|
|
39
|
+
acts_as_statused(
|
|
40
|
+
:draft, # Just Started
|
|
41
|
+
:conflicted, # Conflict of Interest
|
|
42
|
+
:accepted, # Accepted
|
|
43
|
+
:rejected # Rejected
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
acts_as_wizard(
|
|
47
|
+
start: 'Start',
|
|
48
|
+
conflict: 'Conflict of Interest',
|
|
49
|
+
education: 'Education',
|
|
50
|
+
course_amounts: 'Courses',
|
|
51
|
+
experience: 'Work Experience',
|
|
52
|
+
references: 'References',
|
|
53
|
+
files: 'Attach Files',
|
|
54
|
+
declarations: 'Declarations',
|
|
55
|
+
recommendation: 'Recommendation',
|
|
56
|
+
submitted: 'Submitted'
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
belongs_to :applicant
|
|
60
|
+
belongs_to :reviewer, polymorphic: true
|
|
61
|
+
|
|
62
|
+
effective_resource do
|
|
63
|
+
submitted_at :datetime
|
|
64
|
+
recommendation :string
|
|
65
|
+
|
|
66
|
+
comments :text # Rolling comments
|
|
67
|
+
|
|
68
|
+
# Conflict Step
|
|
69
|
+
conflict_of_interest :boolean
|
|
70
|
+
|
|
71
|
+
# Education Step
|
|
72
|
+
education_accepted :boolean
|
|
73
|
+
|
|
74
|
+
# Course Amounts
|
|
75
|
+
course_amounts_accepted :boolean
|
|
76
|
+
|
|
77
|
+
# Courses
|
|
78
|
+
courses_accepted :boolean
|
|
79
|
+
|
|
80
|
+
# Experience Step
|
|
81
|
+
experience_accepted :boolean
|
|
82
|
+
|
|
83
|
+
# References Step
|
|
84
|
+
references_accepted :boolean
|
|
85
|
+
|
|
86
|
+
# References Step
|
|
87
|
+
files_accepted :boolean
|
|
88
|
+
|
|
89
|
+
timestamps
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
scope :deep, -> { includes(:reviewer, applicant: :owner) }
|
|
93
|
+
|
|
94
|
+
with_options(if: -> { current_step == :conflict }) do
|
|
95
|
+
validates :conflict_of_interest, inclusion: { in: [true, false] }
|
|
96
|
+
validates :comments, presence: true, if: -> { conflict_of_interest? }
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
validates :recommendation, absence: true, if: -> { done? && conflict_of_interest? }
|
|
100
|
+
|
|
101
|
+
after_commit(on: :create, if: -> { applicant.completed? }) { notify! }
|
|
102
|
+
|
|
103
|
+
def to_s
|
|
104
|
+
'applicant review'
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def in_progress?
|
|
108
|
+
draft?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def done?
|
|
112
|
+
!draft?
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def conflict_of_interest!
|
|
116
|
+
after_commit { send_email(:applicant_review_conflict_of_interest) }
|
|
117
|
+
|
|
118
|
+
update!(conflict_of_interest: true, recommendation: nil)
|
|
119
|
+
conflicted!
|
|
120
|
+
|
|
121
|
+
applicant.save!
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def accept!
|
|
125
|
+
after_commit { send_email(:applicant_review_completed) }
|
|
126
|
+
|
|
127
|
+
assign_attributes(recommendation: 'Accept')
|
|
128
|
+
accepted!
|
|
129
|
+
|
|
130
|
+
applicant.save!
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def reject!
|
|
134
|
+
after_commit { send_email(:applicant_review_completed) }
|
|
135
|
+
|
|
136
|
+
assign_attributes(recommendation: 'Reject')
|
|
137
|
+
rejected!
|
|
138
|
+
|
|
139
|
+
applicant.save!
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
private
|
|
143
|
+
|
|
144
|
+
def send_email(email)
|
|
145
|
+
EffectiveMemberships.send_email(email, self, email_form_params) unless email_form_skip?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
end
|
|
149
|
+
end
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# EffectiveMembershipsCategory
|
|
4
|
+
#
|
|
5
|
+
# Mark your category model with effective_memberships_category to get all the includes
|
|
6
|
+
|
|
7
|
+
module EffectiveMembershipsCategory
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
module Base
|
|
11
|
+
def effective_memberships_category
|
|
12
|
+
include ::EffectiveMembershipsCategory
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module ClassMethods
|
|
17
|
+
def effective_memberships_category?; true; end
|
|
18
|
+
|
|
19
|
+
def categories
|
|
20
|
+
[]
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
included do
|
|
25
|
+
log_changes(except: :memberships) if respond_to?(:log_changes)
|
|
26
|
+
|
|
27
|
+
# rich_text_body - Used by the select step
|
|
28
|
+
has_many_rich_texts
|
|
29
|
+
|
|
30
|
+
# rich_text_applicant_all_steps_content
|
|
31
|
+
# rich_text_applicant_start_content
|
|
32
|
+
# rich_text_applicant_select_content
|
|
33
|
+
# rich_text_applicant_select_content
|
|
34
|
+
|
|
35
|
+
has_many :membership_categories, class_name: 'Effective::MembershipCategory', as: :category
|
|
36
|
+
|
|
37
|
+
effective_resource do
|
|
38
|
+
title :string
|
|
39
|
+
category :string
|
|
40
|
+
position :integer
|
|
41
|
+
|
|
42
|
+
# Applicants
|
|
43
|
+
can_apply_new :boolean
|
|
44
|
+
can_apply_existing :boolean
|
|
45
|
+
can_apply_restricted :boolean
|
|
46
|
+
can_apply_restricted_ids :text
|
|
47
|
+
|
|
48
|
+
applicant_fee :integer
|
|
49
|
+
applicant_wizard_steps :text
|
|
50
|
+
|
|
51
|
+
min_applicant_educations :integer
|
|
52
|
+
min_applicant_experiences_months :integer
|
|
53
|
+
min_applicant_references :integer
|
|
54
|
+
min_applicant_courses :integer
|
|
55
|
+
min_applicant_files :integer
|
|
56
|
+
|
|
57
|
+
# Applicant Reviews
|
|
58
|
+
min_applicant_reviews :integer
|
|
59
|
+
applicant_review_wizard_steps :text
|
|
60
|
+
|
|
61
|
+
# Prorated Fees
|
|
62
|
+
prorated_jan :integer
|
|
63
|
+
prorated_feb :integer
|
|
64
|
+
prorated_mar :integer
|
|
65
|
+
prorated_apr :integer
|
|
66
|
+
prorated_may :integer
|
|
67
|
+
prorated_jun :integer
|
|
68
|
+
prorated_jul :integer
|
|
69
|
+
prorated_aug :integer
|
|
70
|
+
prorated_sep :integer
|
|
71
|
+
prorated_oct :integer
|
|
72
|
+
prorated_nov :integer
|
|
73
|
+
prorated_dec :integer
|
|
74
|
+
|
|
75
|
+
# Fee Payments
|
|
76
|
+
fee_payment_wizard_steps :text
|
|
77
|
+
|
|
78
|
+
# Renewals
|
|
79
|
+
create_renewal_fees :boolean
|
|
80
|
+
renewal_fee :integer
|
|
81
|
+
|
|
82
|
+
create_late_fees :boolean
|
|
83
|
+
late_fee :integer
|
|
84
|
+
|
|
85
|
+
create_bad_standing :boolean
|
|
86
|
+
|
|
87
|
+
# Pricing
|
|
88
|
+
qb_item_name :string
|
|
89
|
+
tax_exempt :boolean
|
|
90
|
+
|
|
91
|
+
timestamps
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
serialize :can_apply_restricted_ids, Array
|
|
95
|
+
serialize :applicant_wizard_steps, Array
|
|
96
|
+
serialize :fee_payment_wizard_steps, Array
|
|
97
|
+
|
|
98
|
+
scope :deep, -> { includes(:rich_texts) }
|
|
99
|
+
scope :sorted, -> { order(:position) }
|
|
100
|
+
|
|
101
|
+
scope :can_apply, -> {
|
|
102
|
+
where(can_apply_new: true)
|
|
103
|
+
.or(where(can_apply_existing: true))
|
|
104
|
+
.or(where(can_apply_restricted: true))
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
# For the create_fees rake task
|
|
108
|
+
scope :create_renewal_fees, -> { where(create_renewal_fees: true) }
|
|
109
|
+
scope :create_late_fees, -> { where(create_late_fees: true) }
|
|
110
|
+
scope :create_bad_standing, -> { where(create_bad_standing: true) }
|
|
111
|
+
|
|
112
|
+
validates :title, presence: true, uniqueness: true
|
|
113
|
+
validates :position, presence: true
|
|
114
|
+
|
|
115
|
+
after_initialize(if: -> { new_record? }) do
|
|
116
|
+
self.applicant_wizard_steps = EffectiveMemberships.Applicant.all_wizard_steps
|
|
117
|
+
self.applicant_review_wizard_steps = EffectiveMemberships.ApplicantReview.all_wizard_steps
|
|
118
|
+
self.fee_payment_wizard_steps = EffectiveMemberships.FeePayment.all_wizard_steps
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
before_validation do
|
|
122
|
+
self.position ||= (self.class.pluck(:position).compact.max || -1) + 1
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
with_options(if: -> { can_apply? }) do
|
|
126
|
+
validates :can_apply_restricted_ids, presence: true, if: -> { can_apply_restricted? }
|
|
127
|
+
|
|
128
|
+
validates :applicant_fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
129
|
+
validates :prorated_jan, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
130
|
+
validates :prorated_feb, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
131
|
+
validates :prorated_mar, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
132
|
+
validates :prorated_apr, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
133
|
+
validates :prorated_may, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
134
|
+
validates :prorated_jun, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
135
|
+
validates :prorated_jul, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
136
|
+
validates :prorated_aug, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
137
|
+
validates :prorated_sep, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
138
|
+
validates :prorated_oct, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
139
|
+
validates :prorated_nov, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
140
|
+
validates :prorated_dec, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# Instance Methods
|
|
145
|
+
|
|
146
|
+
def to_s
|
|
147
|
+
title.presence || 'New Membership Category'
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def can_apply?
|
|
151
|
+
can_apply_new? || can_apply_existing? || can_apply_restricted?
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def prorated_fee(date:)
|
|
155
|
+
send("prorated_#{date.strftime('%b').downcase}").to_i
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def discount_fee(date:)
|
|
159
|
+
0 - prorated_fee(date: date)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def can_apply_restricted_ids
|
|
163
|
+
Array(self[:can_apply_restricted_ids]) - [nil, '']
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def applicant_wizard_steps
|
|
167
|
+
(Array(self[:applicant_wizard_steps]) - [nil, '']).map(&:to_sym)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def fee_payment_wizard_steps
|
|
171
|
+
(Array(self[:fee_payment_wizard_steps]) - [nil, '']).map(&:to_sym)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def applicant_review_wizard_steps
|
|
175
|
+
(Array(self[:applicant_review_wizard_steps]) - [nil, '']).map(&:to_sym)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def applicant_wizard_steps_collection
|
|
179
|
+
wizard_steps = EffectiveMemberships.Applicant.const_get(:WIZARD_STEPS)
|
|
180
|
+
required_steps = EffectiveMemberships.Applicant.required_wizard_steps
|
|
181
|
+
|
|
182
|
+
wizard_steps.map do |step, title|
|
|
183
|
+
[title, step, 'disabled' => required_steps.include?(step)]
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def fee_payment_wizard_steps_collection
|
|
188
|
+
wizard_steps = EffectiveMemberships.FeePayment.const_get(:WIZARD_STEPS)
|
|
189
|
+
required_steps = EffectiveMemberships.FeePayment.required_wizard_steps
|
|
190
|
+
|
|
191
|
+
wizard_steps.map do |step, title|
|
|
192
|
+
[title, step, 'disabled' => required_steps.include?(step)]
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
end
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# EffectiveMembershipsFeePayment
|
|
4
|
+
#
|
|
5
|
+
# Mark your model with effective_memberships_fee_payment to get all the includes
|
|
6
|
+
|
|
7
|
+
module EffectiveMembershipsFeePayment
|
|
8
|
+
extend ActiveSupport::Concern
|
|
9
|
+
|
|
10
|
+
module Base
|
|
11
|
+
def effective_memberships_fee_payment
|
|
12
|
+
include ::EffectiveMembershipsFeePayment
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module ClassMethods
|
|
17
|
+
def effective_memberships_fee_payment?; true; end
|
|
18
|
+
|
|
19
|
+
def all_wizard_steps
|
|
20
|
+
const_get(:WIZARD_STEPS).keys
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def required_wizard_steps
|
|
24
|
+
[:start, :summary, :billing, :checkout, :submitted]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
included do
|
|
29
|
+
acts_as_purchasable_parent
|
|
30
|
+
acts_as_tokened
|
|
31
|
+
|
|
32
|
+
acts_as_statused(
|
|
33
|
+
:draft, # Just Started
|
|
34
|
+
:submitted # All Done
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
acts_as_wizard(
|
|
38
|
+
start: 'Start',
|
|
39
|
+
demographics: 'Demographics',
|
|
40
|
+
declarations: 'Declarations',
|
|
41
|
+
summary: 'Review',
|
|
42
|
+
billing: 'Billing Address',
|
|
43
|
+
checkout: 'Checkout',
|
|
44
|
+
submitted: 'Submitted'
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
log_changes(except: :wizard_steps) if respond_to?(:log_changes)
|
|
48
|
+
|
|
49
|
+
# Declarations Step
|
|
50
|
+
attr_accessor :declare_code_of_ethics
|
|
51
|
+
attr_accessor :declare_truth
|
|
52
|
+
|
|
53
|
+
# Application Namespace
|
|
54
|
+
belongs_to :owner, polymorphic: true
|
|
55
|
+
accepts_nested_attributes_for :owner
|
|
56
|
+
|
|
57
|
+
# Like maybe optionally it makes sense.
|
|
58
|
+
belongs_to :category, polymorphic: true, optional: true
|
|
59
|
+
|
|
60
|
+
has_many :fees, -> { order(:id) }, as: :parent, class_name: 'Effective::Fee', dependent: :nullify
|
|
61
|
+
accepts_nested_attributes_for :fees, reject_if: :all_blank, allow_destroy: true
|
|
62
|
+
|
|
63
|
+
# Effective Namespace
|
|
64
|
+
has_many :orders, -> { order(:id) }, as: :parent, class_name: 'Effective::Order', dependent: :nullify
|
|
65
|
+
accepts_nested_attributes_for :orders
|
|
66
|
+
|
|
67
|
+
effective_resource do
|
|
68
|
+
# Acts as Statused
|
|
69
|
+
status :string, permitted: false
|
|
70
|
+
status_steps :text, permitted: false
|
|
71
|
+
|
|
72
|
+
# Dates
|
|
73
|
+
period :date
|
|
74
|
+
submitted_at :datetime
|
|
75
|
+
|
|
76
|
+
# Acts as Wizard
|
|
77
|
+
wizard_steps :text, permitted: false
|
|
78
|
+
|
|
79
|
+
timestamps
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
scope :deep, -> { includes(:owner, :category, :orders) }
|
|
83
|
+
scope :sorted, -> { order(:id) }
|
|
84
|
+
|
|
85
|
+
scope :in_progress, -> { where.not(status: [:submitted]) }
|
|
86
|
+
scope :done, -> { where(status: [:submitted]) }
|
|
87
|
+
|
|
88
|
+
before_validation do
|
|
89
|
+
self.period ||= EffectiveMemberships.Registrar.current_period
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
before_validation(if: -> { current_step == :start && owner && owner.membership }) do
|
|
93
|
+
self.category ||= owner.membership.categories.first if owner.membership.categories.length == 1
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
validates :period, presence: true
|
|
97
|
+
|
|
98
|
+
# All Steps validations
|
|
99
|
+
validates :owner, presence: true
|
|
100
|
+
|
|
101
|
+
# Declarations Step
|
|
102
|
+
with_options(if: -> { current_step == :declarations }) do
|
|
103
|
+
validates :declare_code_of_ethics, acceptance: true
|
|
104
|
+
validates :declare_truth, acceptance: true
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Clear required steps memoization
|
|
108
|
+
after_save { @_required_steps = nil }
|
|
109
|
+
|
|
110
|
+
# This required_steps is defined inside the included do .. end block so it overrides the acts_as_wizard one.
|
|
111
|
+
def required_steps
|
|
112
|
+
return self.class.test_required_steps if Rails.env.test? && self.class.test_required_steps.present?
|
|
113
|
+
|
|
114
|
+
@_required_steps ||= begin
|
|
115
|
+
wizard_steps = self.class.all_wizard_steps
|
|
116
|
+
required_steps = self.class.required_wizard_steps
|
|
117
|
+
|
|
118
|
+
fee_payment_steps = Array(category&.fee_payment_wizard_steps)
|
|
119
|
+
|
|
120
|
+
wizard_steps.select do |step|
|
|
121
|
+
required_steps.include?(step) || category.blank? || fee_payment_steps.include?(step)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
after_purchase do |_order|
|
|
127
|
+
raise('expected submit_order to be purchased') unless submit_order&.purchased?
|
|
128
|
+
|
|
129
|
+
submit_purchased!
|
|
130
|
+
after_submit_purchased!
|
|
131
|
+
EffectiveMemberships.Registrar.fee_payment_purchased!(owner)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def to_s
|
|
136
|
+
'Fee Payment'
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Instance Methods
|
|
140
|
+
def in_progress?
|
|
141
|
+
draft?
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def done?
|
|
145
|
+
submitted?
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def can_visit_step?(step)
|
|
149
|
+
can_revisit_completed_steps(step)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def outstanding_fees
|
|
153
|
+
owner&.outstanding_fee_payment_fees
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# All Fees and Orders
|
|
157
|
+
def submit_fees
|
|
158
|
+
fees
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def submit_order
|
|
162
|
+
orders.first
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# We take over the owner's outstanding fees.
|
|
166
|
+
def find_or_build_submit_fees
|
|
167
|
+
Array(outstanding_fees).each { |fee| fees << fee }
|
|
168
|
+
submit_fees
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def find_or_build_submit_order
|
|
172
|
+
order = submit_order || orders.build(user: owner)
|
|
173
|
+
|
|
174
|
+
submit_fees.each do |fee|
|
|
175
|
+
order.add(fee) unless order.purchasables.include?(fee)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
order.billing_address = owner.billing_address if owner.billing_address.present?
|
|
179
|
+
|
|
180
|
+
order
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
# Should be indempotent.
|
|
184
|
+
def build_submit_fees_and_order
|
|
185
|
+
return false if was_submitted?
|
|
186
|
+
|
|
187
|
+
fees = find_or_build_submit_fees()
|
|
188
|
+
raise('already has purchased submit fees') if fees.any? { |fee| fee.purchased? }
|
|
189
|
+
|
|
190
|
+
order = find_or_build_submit_order()
|
|
191
|
+
raise('already has purchased submit order') if order.purchased?
|
|
192
|
+
|
|
193
|
+
true
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
# Owner clicks on the Billing Submit. Next step is Checkout
|
|
197
|
+
def billing!
|
|
198
|
+
ready!
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def ready!
|
|
202
|
+
build_submit_fees_and_order
|
|
203
|
+
save!
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# Called automatically via after_purchase hook above
|
|
208
|
+
def submit_purchased!
|
|
209
|
+
return false if was_submitted?
|
|
210
|
+
|
|
211
|
+
wizard_steps[:checkout] = Time.zone.now
|
|
212
|
+
submit!
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# A hook to extend
|
|
216
|
+
def after_submit_purchased!
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
# Draft -> Submitted
|
|
220
|
+
def submit!
|
|
221
|
+
raise('already submitted') if was_submitted?
|
|
222
|
+
raise('expected a purchased order') unless submit_order&.purchased?
|
|
223
|
+
|
|
224
|
+
wizard_steps[:checkout] ||= Time.zone.now
|
|
225
|
+
wizard_steps[:submitted] = Time.zone.now
|
|
226
|
+
submitted!
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
end
|