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