effective_memberships 0.3.9 → 0.3.12
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/applicants_controller.rb +14 -0
- data/app/controllers/effective/applicants_controller.rb +2 -0
- data/app/datatables/admin/effective_applicants_datatable.rb +7 -2
- data/app/datatables/admin/effective_fees_datatable.rb +5 -3
- data/app/datatables/admin/effective_memberships_datatable.rb +38 -1
- data/app/datatables/effective_applicants_datatable.rb +10 -4
- data/app/datatables/effective_memberships_directory_datatable.rb +1 -1
- data/app/helpers/effective_memberships_helper.rb +9 -0
- data/app/mailers/effective/memberships_mailer.rb +16 -6
- data/app/models/concerns/effective_memberships_applicant.rb +71 -18
- data/app/models/concerns/effective_memberships_owner.rb +8 -2
- data/app/models/effective/membership.rb +2 -0
- data/app/views/admin/applicants/_form.html.haml +10 -6
- data/app/views/admin/applicants/_form_approve.html.haml +1 -5
- data/app/views/admin/applicants/_form_complete.html.haml +8 -0
- data/app/views/admin/applicants/_form_missing_info.html.haml +11 -0
- data/app/views/admin/applicants/_form_process.html.haml +16 -12
- data/app/views/admin/applicants/_status.html.haml +67 -49
- data/app/views/effective/applicants/_missing_info.html.haml +18 -0
- data/app/views/effective/applicants/_summary.html.haml +1 -1
- data/app/views/effective/applicants/submitted.html.haml +11 -9
- data/app/views/effective/applicants/summary.html.haml +7 -1
- data/app/views/effective/memberships_mailer/applicant_completed.liquid +15 -0
- data/app/views/effective/memberships_mailer/applicant_missing_info.liquid +17 -0
- data/config/effective_memberships.rb +5 -0
- data/db/migrate/01_create_effective_memberships.rb.erb +4 -0
- data/lib/effective_memberships/version.rb +1 -1
- data/lib/effective_memberships.rb +5 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 32668e9dd393f60b922e5133dccf0204b0506f6a6fcff74f955be98e417b9398
|
4
|
+
data.tar.gz: 9b15d17b3e60142c3db939e1ecedd92a028540fb20234443a2c46be8e7427dea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b91b4b36706dce52f0fb43962a87977163364adcc0fb453d494f1e05895bf9e8edc737cf8a10df51d6cf5cf8da415957f0239ae1ef57de5425471bb68dc35e04
|
7
|
+
data.tar.gz: 14f41d1145244e763dab621c0db7cbfbea2e0ee2a5ad88eceaf953da5634a19ba562e44aff38557561a5ed60a6aee6d758b1c980180652fbba9d673f4b56241e
|
@@ -8,6 +8,20 @@ module Admin
|
|
8
8
|
resource_scope -> { EffectiveMemberships.Applicant.deep.all }
|
9
9
|
datatable -> { Admin::EffectiveApplicantsDatatable.new }
|
10
10
|
|
11
|
+
submit :complete, 'Complete Applicant', success: -> {
|
12
|
+
[
|
13
|
+
"Successfully completed #{resource.owner} #{resource}",
|
14
|
+
("and sent #{resource.owner.email} a notification" unless resource.email_form_skip)
|
15
|
+
].compact.join(' ')
|
16
|
+
}
|
17
|
+
|
18
|
+
submit :missing, 'Missing Info Applicant', success: -> {
|
19
|
+
[
|
20
|
+
"Successfully marked #{resource.owner} #{resource} as missing info",
|
21
|
+
("and sent #{resource.owner.email} a notification" unless resource.email_form_skip)
|
22
|
+
].compact.join(' ')
|
23
|
+
}
|
24
|
+
|
11
25
|
submit :approve, 'Approve Applicant', success: -> {
|
12
26
|
[
|
13
27
|
"Successfully approved #{resource.owner} #{resource}",
|
@@ -11,14 +11,19 @@ module Admin
|
|
11
11
|
order :id
|
12
12
|
col :id, visible: false
|
13
13
|
|
14
|
-
col :status
|
14
|
+
col :status, search: effective_memberships_status_collection()
|
15
15
|
|
16
16
|
col :created_at, label: 'Created', as: :date, visible: false
|
17
17
|
col :updated_at, label: 'Updated', visible: false
|
18
18
|
|
19
19
|
col :submitted_at, label: 'Submitted', visible: false, as: :date
|
20
20
|
col :completed_at, label: 'Completed', visible: false, as: :date
|
21
|
-
col :
|
21
|
+
col :missing_info_at, label: 'Missing Info', visible: false, as: :date
|
22
|
+
|
23
|
+
if EffectiveMemberships.applicant_reviews?
|
24
|
+
col :reviewed_at, label: 'Reviewed', visible: false, as: :date
|
25
|
+
end
|
26
|
+
|
22
27
|
col :approved_at, label: 'Approved', visible: false, as: :date
|
23
28
|
|
24
29
|
col :owner
|
@@ -33,7 +33,9 @@ module Admin
|
|
33
33
|
|
34
34
|
col :category, search: { collection: EffectiveMemberships.Category.all, polymorphic: false }
|
35
35
|
|
36
|
-
|
36
|
+
unless attributes[:total] == false
|
37
|
+
aggregate :total
|
38
|
+
end
|
37
39
|
|
38
40
|
if attributes[:applicant_id]
|
39
41
|
actions_col(new: false)
|
@@ -63,11 +65,11 @@ module Admin
|
|
63
65
|
end
|
64
66
|
|
65
67
|
def applicant
|
66
|
-
@applicant ||= EffectiveMemberships.Applicant.
|
68
|
+
@applicant ||= EffectiveMemberships.Applicant.where(id: attributes[:applicant_id]).first!
|
67
69
|
end
|
68
70
|
|
69
71
|
def fee_payment
|
70
|
-
@fee_payment ||= EffectiveMemberships.FeePayment.
|
72
|
+
@fee_payment ||= EffectiveMemberships.FeePayment.where(id: attributes[:fee_payment_id]).first!
|
71
73
|
end
|
72
74
|
|
73
75
|
end
|
@@ -24,11 +24,48 @@ module Admin
|
|
24
24
|
col :bad_standing_admin, visible: false
|
25
25
|
col :bad_standing_reason, visible: false
|
26
26
|
|
27
|
+
col :email do |membership|
|
28
|
+
email = membership.owner.try(:email)
|
29
|
+
mail_to(email) if email.present?
|
30
|
+
end
|
31
|
+
|
32
|
+
col :phone do |membership|
|
33
|
+
membership.owner.try(:phone) || membership.owner.try(:home_phone) || membership.owner.try(:cell_phone)
|
34
|
+
end
|
35
|
+
|
36
|
+
col :address do |membership|
|
37
|
+
membership.owner.try(:addresses).try(:first).try(:to_html)
|
38
|
+
end
|
39
|
+
|
40
|
+
col :address1, visible: false do |membership|
|
41
|
+
membership.owner.try(:addresses).try(:first).try(:address1)
|
42
|
+
end
|
43
|
+
|
44
|
+
col :address2, visible: false do |membership|
|
45
|
+
membership.owner.try(:addresses).try(:first).try(:address2)
|
46
|
+
end
|
47
|
+
|
48
|
+
col :city, visible: false do |membership|
|
49
|
+
membership.owner.try(:addresses).try(:first).try(:city)
|
50
|
+
end
|
51
|
+
|
52
|
+
col :province, visible: false do |membership|
|
53
|
+
membership.owner.try(:addresses).try(:first).try(:province)
|
54
|
+
end
|
55
|
+
|
56
|
+
col :country, visible: false do |membership|
|
57
|
+
membership.owner.try(:addresses).try(:first).try(:country)
|
58
|
+
end
|
59
|
+
|
60
|
+
col :postal_code, visible: false do |membership|
|
61
|
+
membership.owner.try(:addresses).try(:first).try(:postal_code)
|
62
|
+
end
|
63
|
+
|
27
64
|
actions_col
|
28
65
|
end
|
29
66
|
|
30
67
|
collection do
|
31
|
-
memberships = Effective::Membership.deep.all.includes(:
|
68
|
+
memberships = Effective::Membership.deep.all.includes(owner: :addresses)
|
32
69
|
|
33
70
|
raise('expected an owner_id, not user_id') if attributes[:user_id].present?
|
34
71
|
|
@@ -6,14 +6,20 @@ class EffectiveApplicantsDatatable < Effective::Datatable
|
|
6
6
|
col :id, visible: false
|
7
7
|
|
8
8
|
col :category, label: 'Category'
|
9
|
-
col :status
|
9
|
+
col :status, search: effective_memberships_status_collection()
|
10
10
|
|
11
11
|
col :created_at, label: 'Created', as: :date
|
12
12
|
col :updated_at, label: 'Updated', as: :date, visible: false
|
13
|
+
|
13
14
|
col :submitted_at, label: 'Submitted', as: :date
|
14
|
-
col :completed_at, label: 'Completed', as: :date
|
15
|
-
col :
|
16
|
-
|
15
|
+
col :completed_at, label: 'Completed', as: :date, visible: false
|
16
|
+
col :missing_info_at, label: 'Missing Info', as: :date, visible: false
|
17
|
+
|
18
|
+
if EffectiveMemberships.applicant_reviews?
|
19
|
+
col :reviewed_at, label: 'Reviewed', as: :date
|
20
|
+
end
|
21
|
+
|
22
|
+
col :approved_at, label: 'Approved', as: :date
|
17
23
|
|
18
24
|
col :orders
|
19
25
|
|
@@ -11,7 +11,7 @@ class EffectiveMembershipsDirectoryDatatable < Effective::Datatable
|
|
11
11
|
end
|
12
12
|
|
13
13
|
collection do
|
14
|
-
scope = Effective::Membership.deep.includes(:owner)
|
14
|
+
scope = Effective::Membership.deep.good_standing.includes(:owner)
|
15
15
|
|
16
16
|
archived_klasses.each do |klass|
|
17
17
|
scope = scope.where.not(owner_id: klass.archived.select('id'), owner_type: klass.name)
|
@@ -1,2 +1,11 @@
|
|
1
1
|
module EffectiveMembershipsHelper
|
2
|
+
|
3
|
+
def effective_memberships_status_collection
|
4
|
+
EffectiveMemberships.Applicant::STATUSES.map do |status|
|
5
|
+
next if status == :reviewed && !EffectiveMemberships.applicant_reviews?
|
6
|
+
|
7
|
+
[status.to_s.gsub('_', ' '), status]
|
8
|
+
end.compact
|
9
|
+
end
|
10
|
+
|
2
11
|
end
|
@@ -5,14 +5,24 @@ module Effective
|
|
5
5
|
default from: -> { EffectiveMemberships.mailer_sender }
|
6
6
|
layout -> { EffectiveMemberships.mailer_layout || 'effective_memberships_mailer_layout' }
|
7
7
|
|
8
|
+
def applicant_completed(resource, opts = {})
|
9
|
+
@assigns = assigns_for(resource)
|
10
|
+
mail(to: resource.owner.email, **headers_for(resource, opts))
|
11
|
+
end
|
12
|
+
|
13
|
+
def applicant_missing_info(resource, opts = {})
|
14
|
+
@assigns = assigns_for(resource)
|
15
|
+
mail(to: resource.owner.email, **headers_for(resource, opts))
|
16
|
+
end
|
17
|
+
|
8
18
|
def applicant_approved(resource, opts = {})
|
9
19
|
@assigns = assigns_for(resource)
|
10
|
-
mail(to:
|
20
|
+
mail(to: resource.owner.email, **headers_for(resource, opts))
|
11
21
|
end
|
12
22
|
|
13
23
|
def applicant_declined(resource, opts = {})
|
14
24
|
@assigns = assigns_for(resource)
|
15
|
-
mail(to:
|
25
|
+
mail(to: resource.owner.email, **headers_for(resource, opts))
|
16
26
|
end
|
17
27
|
|
18
28
|
def applicant_reference_notification(resource, opts = {})
|
@@ -49,11 +59,11 @@ module Effective
|
|
49
59
|
|
50
60
|
url: effective_memberships.applicant_url(applicant),
|
51
61
|
admin_url: effective_memberships.edit_admin_applicant_url(applicant),
|
52
|
-
}
|
53
62
|
|
54
|
-
|
55
|
-
|
56
|
-
|
63
|
+
# Optional
|
64
|
+
declined_reason: applicant.declined_reason.presence,
|
65
|
+
missing_info_reason: applicant.missing_info_reason.presence
|
66
|
+
}.compact
|
57
67
|
|
58
68
|
{ applicant: values }
|
59
69
|
end
|
@@ -32,12 +32,13 @@ module EffectiveMembershipsApplicant
|
|
32
32
|
acts_as_tokened
|
33
33
|
|
34
34
|
acts_as_statused(
|
35
|
-
:draft,
|
36
|
-
:submitted,
|
37
|
-
:
|
38
|
-
:
|
39
|
-
:
|
40
|
-
:
|
35
|
+
:draft, # Just Started
|
36
|
+
:submitted, # Completed wizard. Paid applicant fee.
|
37
|
+
:missing_info, # Admin has indicated information is missing. The applicant can edit applicant and add info
|
38
|
+
:completed, # Admin has received all deliverables. The application is complete and ready for review.
|
39
|
+
:reviewed, # All applicant reviews completed
|
40
|
+
:declined, # Exit state. Application was declined.
|
41
|
+
:approved # Exit state. Application was approved.
|
41
42
|
)
|
42
43
|
|
43
44
|
acts_as_wizard(
|
@@ -121,18 +122,22 @@ module EffectiveMembershipsApplicant
|
|
121
122
|
declined_at :datetime
|
122
123
|
declined_reason :text
|
123
124
|
|
125
|
+
# Missing Info
|
126
|
+
missing_info_at :datetime
|
127
|
+
missing_info_reason :text
|
128
|
+
|
124
129
|
# Applicant Educations
|
125
|
-
applicant_educations_details
|
130
|
+
applicant_educations_details :text
|
126
131
|
|
127
132
|
# Applicant Experiences
|
128
|
-
applicant_experiences_months
|
129
|
-
applicant_experiences_details
|
133
|
+
applicant_experiences_months :integer
|
134
|
+
applicant_experiences_details :text
|
130
135
|
|
131
136
|
# Additional Information
|
132
|
-
additional_information
|
137
|
+
additional_information :text
|
133
138
|
|
134
139
|
# Acts as Wizard
|
135
|
-
wizard_steps
|
140
|
+
wizard_steps :text, permitted: false
|
136
141
|
|
137
142
|
timestamps
|
138
143
|
end
|
@@ -264,9 +269,12 @@ module EffectiveMembershipsApplicant
|
|
264
269
|
# Admin Decline
|
265
270
|
validates :declined_reason, presence: true, if: -> { declined? }
|
266
271
|
|
272
|
+
# Admin Missing Info
|
273
|
+
validates :missing_info_reason, presence: true, if: -> { missing_info? }
|
274
|
+
|
267
275
|
# These two try completed and try reviewed
|
268
|
-
before_save(if: -> { submitted? }) { complete! }
|
269
|
-
before_save(if: -> { completed? }) { review! }
|
276
|
+
# before_save(if: -> { submitted? }) { complete! }
|
277
|
+
# before_save(if: -> { completed? }) { review! }
|
270
278
|
|
271
279
|
# Clear required steps memoization
|
272
280
|
after_save { @_required_steps = nil }
|
@@ -290,6 +298,14 @@ module EffectiveMembershipsApplicant
|
|
290
298
|
end
|
291
299
|
end
|
292
300
|
|
301
|
+
def can_visit_step?(step)
|
302
|
+
if missing_info?
|
303
|
+
return [:start, :select, :billing, :checkout].exclude?(step)
|
304
|
+
end
|
305
|
+
|
306
|
+
can_revisit_completed_steps(step)
|
307
|
+
end
|
308
|
+
|
293
309
|
# All Fees and Orders
|
294
310
|
def submit_fees
|
295
311
|
# Find or build submit fee
|
@@ -374,6 +390,10 @@ module EffectiveMembershipsApplicant
|
|
374
390
|
approved? || declined?
|
375
391
|
end
|
376
392
|
|
393
|
+
def status_label
|
394
|
+
(status_was || status).to_s.gsub('_', ' ')
|
395
|
+
end
|
396
|
+
|
377
397
|
def summary
|
378
398
|
case status_was
|
379
399
|
when 'draft'
|
@@ -388,6 +408,8 @@ module EffectiveMembershipsApplicant
|
|
388
408
|
else
|
389
409
|
"This application has been completed and is now ready for an admin to approve or decline it. If approved, prorated fees will be generated."
|
390
410
|
end
|
411
|
+
when 'missing_info'
|
412
|
+
"Missing the following information: <ul><li>#{missing_info_reason}</li></ul>"
|
391
413
|
when 'reviewed'
|
392
414
|
"This application has been reviewed and is now ready for an admin to approve or decline it. If approved, prorated fees will be generated."
|
393
415
|
when 'approved'
|
@@ -489,7 +511,8 @@ module EffectiveMembershipsApplicant
|
|
489
511
|
min_applicant_references > 0
|
490
512
|
end
|
491
513
|
|
492
|
-
# When an application is submitted, these must be done to go to completed
|
514
|
+
# When an application is submitted, these must be done to go to completed.
|
515
|
+
# An Admin can override this and just set them to completed.
|
493
516
|
def completed_requirements
|
494
517
|
{
|
495
518
|
'Applicant References' => (!applicant_references_required? || applicant_references.count(&:completed?) >= min_applicant_references)
|
@@ -497,9 +520,34 @@ module EffectiveMembershipsApplicant
|
|
497
520
|
end
|
498
521
|
|
499
522
|
def complete!
|
500
|
-
|
501
|
-
|
523
|
+
raise('applicant must have been submitted to complete!') unless was_submitted?
|
524
|
+
|
525
|
+
# Let an admin ignore these requirements if need be
|
526
|
+
# return false unless submitted? && completed_requirements.values.all?
|
527
|
+
|
528
|
+
assign_attributes(missing_info_reason: nil)
|
502
529
|
completed!
|
530
|
+
|
531
|
+
after_commit { send_email(:applicant_completed) }
|
532
|
+
true
|
533
|
+
end
|
534
|
+
|
535
|
+
def missing!
|
536
|
+
raise('applicant must have been submitted to missing!') unless was_submitted?
|
537
|
+
|
538
|
+
missing_info!
|
539
|
+
|
540
|
+
after_commit { send_email(:applicant_missing_info) }
|
541
|
+
true
|
542
|
+
end
|
543
|
+
|
544
|
+
def resubmit!
|
545
|
+
raise('applicant must have been submitted and missing info to resubmit!') unless was_submitted? && was_missing_info?
|
546
|
+
raise('already submitted') if submitted?
|
547
|
+
raise('expected a purchased order') unless submit_order&.purchased?
|
548
|
+
|
549
|
+
assign_attributes(skip_to_step: :submitted, submitted_at: Time.zone.now)
|
550
|
+
submitted!
|
503
551
|
end
|
504
552
|
|
505
553
|
# Completed -> Reviewed requirements
|
@@ -512,6 +560,7 @@ module EffectiveMembershipsApplicant
|
|
512
560
|
end
|
513
561
|
|
514
562
|
# When an application is completed, these must be done to go to reviewed
|
563
|
+
# An Admin can override this and just set them to reviewed.
|
515
564
|
def reviewed_requirements
|
516
565
|
{
|
517
566
|
'Applicant Reviews' => (!applicant_reviews_required? || applicant_reviews.count(&:completed?) >= min_applicant_reviews)
|
@@ -519,8 +568,10 @@ module EffectiveMembershipsApplicant
|
|
519
568
|
end
|
520
569
|
|
521
570
|
def review!
|
522
|
-
|
523
|
-
|
571
|
+
raise('applicant must have been submitted to review!') unless was_submitted?
|
572
|
+
|
573
|
+
# Let an admin ignore these requirements if need be
|
574
|
+
# return false unless completed? && reviewed_requirements.values.all?
|
524
575
|
reviewed!
|
525
576
|
end
|
526
577
|
|
@@ -532,6 +583,8 @@ module EffectiveMembershipsApplicant
|
|
532
583
|
# Complete the wizard step. Just incase this is run out of order.
|
533
584
|
wizard_steps[:checkout] ||= Time.zone.now
|
534
585
|
wizard_steps[:submitted] ||= Time.zone.now
|
586
|
+
assign_attributes(missing_info_reason: nil)
|
587
|
+
|
535
588
|
approved!
|
536
589
|
|
537
590
|
if apply_to_join?
|
@@ -56,7 +56,9 @@ module EffectiveMembershipsOwner
|
|
56
56
|
owners = organizations if self.class.respond_to?(:effective_organizations_user?)
|
57
57
|
owners = users if self.class.respond_to?(:effective_organizations_organization?)
|
58
58
|
|
59
|
-
owners = Array(owners)
|
59
|
+
owners = Array(owners)
|
60
|
+
.select { |owner| owner.class.respond_to?(:effective_memberships_owner?) }
|
61
|
+
.reject { |owner| owner.try(:archived?) }
|
60
62
|
|
61
63
|
owners.presence || [self]
|
62
64
|
end
|
@@ -73,7 +75,11 @@ module EffectiveMembershipsOwner
|
|
73
75
|
|
74
76
|
def organization_membership_present?(except: nil)
|
75
77
|
return false unless self.class.respond_to?(:effective_organizations_user?)
|
76
|
-
|
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? }
|
77
83
|
end
|
78
84
|
|
79
85
|
def assign_member_role
|
@@ -29,6 +29,8 @@ module Effective
|
|
29
29
|
scope :deep, -> { includes(membership_categories: :category) }
|
30
30
|
scope :sorted, -> { order(:id) }
|
31
31
|
|
32
|
+
scope :good_standing, -> { where(bad_standing: [nil, false]) }
|
33
|
+
|
32
34
|
scope :with_paid_fees_through, -> (period = nil) {
|
33
35
|
where(arel_table[:fees_paid_period].gteq(period || EffectiveMemberships.Registrar.current_period))
|
34
36
|
}
|
@@ -25,13 +25,17 @@
|
|
25
25
|
= tab 'References' do
|
26
26
|
.mb-4= render_inline_datatable(Admin::EffectiveApplicantReferencesDatatable.new(applicant: applicant))
|
27
27
|
|
28
|
-
- if applicant.fees.present?
|
28
|
+
- if applicant.fees.present? || applicant.orders.present?
|
29
29
|
= tab 'Fees' do
|
30
|
-
.mb-4
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
30
|
+
.mb-4
|
31
|
+
%h2 Fees
|
32
|
+
- datatable = Admin::EffectiveFeesDatatable.new(applicant: applicant, total: false)
|
33
|
+
= render_datatable(datatable, simple: true, inline: true)
|
34
|
+
|
35
|
+
.mb-4
|
36
|
+
%h2 Orders
|
37
|
+
- datatable = Admin::EffectiveOrdersDatatable.new(parent: applicant, owner: applicant.owner, user: applicant.owner, total: false)
|
38
|
+
= render_datatable(datatable, simple: true)
|
35
39
|
|
36
40
|
- if applicant.owner.applicants.any? { |other| other.was_submitted? && other.id != applicant.id }
|
37
41
|
= tab 'Other Applications' do
|
@@ -1,13 +1,9 @@
|
|
1
1
|
= effective_form_with(model: [:admin, applicant], engine: true) do |f|
|
2
|
-
%p The #{applicant} will be <strong>approved</strong> to the following membership category
|
3
|
-
|
4
|
-
%h3 Category
|
5
|
-
= f.static_field :category, label: 'Applied for'
|
2
|
+
%p The #{applicant} will be <strong>approved</strong> to the following membership category:
|
6
3
|
|
7
4
|
- categories = EffectiveMemberships.Category.all
|
8
5
|
= f.select :category_id, categories, label: 'Approve to'
|
9
6
|
|
10
|
-
%h3 Number
|
11
7
|
%p
|
12
8
|
- if applicant.owner.membership&.number_was.present?
|
13
9
|
The member will keep their existing membership number: #{applicant.owner.membership.number}.
|
@@ -0,0 +1,8 @@
|
|
1
|
+
= effective_form_with(model: [:admin, applicant], engine: true) do |f|
|
2
|
+
%p The #{applicant} will be <strong>completed</strong>. All deliverables have been received and all requirements completed.
|
3
|
+
|
4
|
+
%h3 Email to send
|
5
|
+
%p The following email will be sent:
|
6
|
+
= email_form_fields(f, :applicant_completed)
|
7
|
+
|
8
|
+
= f.submit 'Complete Applicant', border: false, center: true, 'data-confirm': "Complete #{f.object.owner}?"
|
@@ -0,0 +1,11 @@
|
|
1
|
+
= effective_form_with(model: [:admin, applicant], engine: true) do |f|
|
2
|
+
%p This applicant will be marked as <strong>missing information</strong> with the following:
|
3
|
+
|
4
|
+
= f.text_field :missing_info_reason, required: true, label: 'Explanation of missing info'
|
5
|
+
|
6
|
+
%h3 Email to send
|
7
|
+
|
8
|
+
%p The following email will be sent:
|
9
|
+
= email_form_fields(f, :applicant_missing_info)
|
10
|
+
|
11
|
+
= f.submit 'Missing Info Applicant', border: false, center: true, 'data-confirm': "Missing Info #{f.object.owner}?"
|
@@ -1,18 +1,22 @@
|
|
1
1
|
%p
|
2
|
-
%span.badge.badge-secondary= applicant.
|
2
|
+
%span.badge.badge-secondary= applicant.status_label
|
3
3
|
= applicant.summary
|
4
4
|
|
5
|
-
|
5
|
+
%p Process applicant:
|
6
|
+
|
7
|
+
= accordion do
|
8
|
+
- if EffectiveResources.authorized?(self, :complete, applicant)
|
9
|
+
= collapse 'Complete this Applicant' do
|
10
|
+
= render('admin/applicants/form_complete', applicant: applicant)
|
11
|
+
|
12
|
+
- if EffectiveResources.authorized?(self, :missing, applicant)
|
13
|
+
= collapse 'Missing Information' do
|
14
|
+
= render('admin/applicants/form_missing_info', applicant: applicant)
|
15
|
+
|
6
16
|
- if EffectiveResources.authorized?(self, :approve, applicant)
|
7
|
-
=
|
8
|
-
|
9
|
-
.card-body
|
10
|
-
%h5.card-title Approve
|
11
|
-
= render('admin/applicants/form_approve', applicant: applicant)
|
17
|
+
= collapse 'Approve this Applicant' do
|
18
|
+
= render('admin/applicants/form_approve', applicant: applicant)
|
12
19
|
|
13
20
|
- if EffectiveResources.authorized?(self, :decline, applicant)
|
14
|
-
=
|
15
|
-
|
16
|
-
.card-body
|
17
|
-
%h5.card-title Decline
|
18
|
-
= render('admin/applicants/form_decline', applicant: applicant)
|
21
|
+
= collapse 'Decline this Applicant' do
|
22
|
+
= render('admin/applicants/form_decline', applicant: applicant)
|
@@ -1,5 +1,5 @@
|
|
1
1
|
%p
|
2
|
-
%span.badge.badge-secondary= applicant.
|
2
|
+
%span.badge.badge-secondary= applicant.status_label
|
3
3
|
= applicant.summary
|
4
4
|
|
5
5
|
%table.table.table-sm.table-striped
|
@@ -11,6 +11,8 @@
|
|
11
11
|
%th
|
12
12
|
- # Next action button
|
13
13
|
%tbody
|
14
|
+
|
15
|
+
-# Draft
|
14
16
|
%tr
|
15
17
|
%td In Progress
|
16
18
|
%td= applicant.created_at.strftime('%F')
|
@@ -21,6 +23,8 @@
|
|
21
23
|
- else
|
22
24
|
= '-'
|
23
25
|
%td
|
26
|
+
|
27
|
+
- # Submitted
|
24
28
|
%tr
|
25
29
|
%td Application Submitted
|
26
30
|
%td= applicant.submitted_at&.strftime('%F') || '-'
|
@@ -30,6 +34,8 @@
|
|
30
34
|
- else
|
31
35
|
= '-'
|
32
36
|
%td
|
37
|
+
|
38
|
+
- # Waiting to Complete
|
33
39
|
%tr
|
34
40
|
%td Waiting to Complete
|
35
41
|
%td= applicant.submitted_at&.strftime('%F') || '-'
|
@@ -63,71 +69,83 @@
|
|
63
69
|
References Not Required
|
64
70
|
|
65
71
|
%td
|
66
|
-
|
67
|
-
|
72
|
+
- if applicant.submitted?
|
73
|
+
= link_to 'Complete Applicant', '#process', 'data-click-tab': true, class: 'btn btn-sm btn-primary'
|
68
74
|
|
69
|
-
|
70
|
-
|
75
|
+
- # Missing Information
|
76
|
+
%tr
|
77
|
+
%td Missing Information
|
78
|
+
%td= applicant.missing_info_at&.strftime('%F') || '-'
|
79
|
+
%td= applicant.missing_info_reason
|
80
|
+
%td
|
71
81
|
|
82
|
+
- # Completed
|
72
83
|
%tr
|
73
|
-
%td Application
|
84
|
+
%td Application Completed
|
74
85
|
%td= applicant.completed_at&.strftime('%F') || '-'
|
75
86
|
%td
|
87
|
+
- if applicant.completed_at.present?
|
88
|
+
= icon('check', class: 'small-1')
|
89
|
+
Done
|
76
90
|
%td
|
77
91
|
|
78
|
-
|
79
|
-
|
80
|
-
%
|
81
|
-
|
82
|
-
|
83
|
-
|
92
|
+
- # Reviewed
|
93
|
+
- if EffectiveMemberships.applicant_reviews?
|
94
|
+
%tr.effective-memberships-applicant-status-reviewed
|
95
|
+
%td Reviews
|
96
|
+
%td= applicant.reviewed_at&.strftime('%F') || '-'
|
97
|
+
%td
|
98
|
+
- applicant.reviewed_requirements.each do |requirement, completed|
|
99
|
+
- next if requirement.to_s == 'Applicant Reviews'
|
84
100
|
|
85
|
-
|
86
|
-
|
87
|
-
|
101
|
+
%p
|
102
|
+
= icon((completed ? 'check' : 'x'), class: 'small-1')
|
103
|
+
= requirement
|
88
104
|
|
89
|
-
|
90
|
-
|
91
|
-
|
105
|
+
- if applicant.applicant_reviews_required?
|
106
|
+
%p
|
107
|
+
- if applicant.reviewed_requirements['Applicant Reviews']
|
108
|
+
= icon('check', class: 'small-1')
|
109
|
+
|
110
|
+
= applicant.applicant_reviews.count(&:completed?)
|
111
|
+
= '/'
|
112
|
+
= applicant.min_applicant_reviews
|
113
|
+
Reviews Completed
|
114
|
+
- else
|
115
|
+
%p
|
92
116
|
= icon('check', class: 'small-1')
|
117
|
+
Reviews Not Required
|
93
118
|
|
94
|
-
|
95
|
-
|
96
|
-
= applicant.min_applicant_reviews
|
97
|
-
Reviews Completed
|
98
|
-
- else
|
99
|
-
%p
|
100
|
-
= icon('check', class: 'small-1')
|
101
|
-
Reviews Not Required
|
119
|
+
%td
|
120
|
+
- # Button to create reviews here
|
102
121
|
|
122
|
+
%tr
|
123
|
+
%td Waiting to Process
|
103
124
|
%td
|
104
|
-
- if
|
125
|
+
- if EffectiveMemberships.applicant_reviews?
|
126
|
+
= applicant.reviewed_at&.strftime('%F') || '-'
|
127
|
+
- else
|
128
|
+
= applicant.completed_at&.strftime('%F') || '-'
|
129
|
+
%td
|
130
|
+
%td
|
131
|
+
- if applicant.was_submitted? && !(applicant.approved? || applicant.declined?)
|
105
132
|
= link_to 'Process Applicant', '#process', 'data-click-tab': true, class: 'btn btn-sm btn-primary'
|
106
133
|
|
107
|
-
|
108
|
-
%
|
109
|
-
|
110
|
-
|
111
|
-
|
134
|
+
%tr
|
135
|
+
%td Processed
|
136
|
+
%td= (applicant.approved_at&.strftime('%F') || applicant.declined_at&.strftime('%F') || '-')
|
137
|
+
%td
|
138
|
+
- if applicant.was_approved? && !applicant.approved?
|
139
|
+
= icon('check', class: 'small-1')
|
140
|
+
Approved
|
141
|
+
|
142
|
+
- elsif applicant.was_declined? || applicant.declined?
|
112
143
|
= icon('check', class: 'small-1')
|
113
144
|
Declined
|
114
145
|
%br
|
115
146
|
= applicant.declined_reason
|
116
|
-
%td
|
117
147
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
%td
|
123
|
-
- if applicant.was_approved?
|
124
|
-
= icon('check', class: 'small-1')
|
125
|
-
Approved
|
126
|
-
- elsif applicant.declined?
|
127
|
-
= icon('check', class: 'small-1')
|
128
|
-
Declined
|
129
|
-
%br
|
130
|
-
= applicant.declined_reason
|
131
|
-
- else
|
132
|
-
= '-'
|
133
|
-
%td
|
148
|
+
- elsif applicant.approved?
|
149
|
+
= icon('check', class: 'small-1')
|
150
|
+
Approved
|
151
|
+
%td
|
@@ -0,0 +1,18 @@
|
|
1
|
+
%h3 Missing Information
|
2
|
+
%p The following information is missing: #{resource.missing_info_reason}.
|
3
|
+
|
4
|
+
%p
|
5
|
+
Please revisit each wizard step and
|
6
|
+
= link_to 'complete all missing information', wizard_path(:demographics)
|
7
|
+
for this application.
|
8
|
+
|
9
|
+
%p
|
10
|
+
Once you're ready, click below to re-submit your application with the updated information.
|
11
|
+
|
12
|
+
%p
|
13
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
14
|
+
= f.hidden_field :id
|
15
|
+
= f.save 'Submit Application', 'data-confirm': "Really submit application?"
|
16
|
+
|
17
|
+
%p
|
18
|
+
%small * No additional payment required.
|
@@ -5,8 +5,7 @@
|
|
5
5
|
- raise('expected a purchased applicant submit_order') unless resource.submit_order&.purchased?
|
6
6
|
|
7
7
|
.alert.alert-success.mb-4
|
8
|
-
This application was submitted on
|
9
|
-
= resource.submit_order.purchased_at.strftime('%F')
|
8
|
+
This application was submitted on #{resource.submitted_at.strftime('%F')}
|
10
9
|
|
11
10
|
- unless resource.approved?
|
12
11
|
.card
|
@@ -20,15 +19,18 @@
|
|
20
19
|
.card
|
21
20
|
.card-body= render 'effective/applicants/summary', applicant: resource
|
22
21
|
|
22
|
+
- if resource.missing_info?
|
23
|
+
= card do
|
24
|
+
= render 'effective/applicants/missing_info', applicant: resource
|
25
|
+
|
23
26
|
- if resource.min_applicant_references.to_i > 0 || resource.applicant_references.present?
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
Click 'New' to add an additional reference, or click 'Notify' to resend the reference request.
|
27
|
+
= card do
|
28
|
+
%h3 Confidential References
|
29
|
+
%p
|
30
|
+
References are automatically sent a reference request.
|
31
|
+
Click 'New' to add an additional reference, or click 'Notify' to resend the reference request.
|
30
32
|
|
31
|
-
|
33
|
+
= render_datatable(EffectiveApplicantReferencesDatatable.new(applicant: resource), inline: true, simple: true)
|
32
34
|
|
33
35
|
.mb-4
|
34
36
|
= collapse('Show application...', card_class: 'my-2') do
|
@@ -5,4 +5,10 @@
|
|
5
5
|
|
6
6
|
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
7
7
|
= f.hidden_field :id
|
8
|
-
|
8
|
+
|
9
|
+
= f.submit(border: false, left: true) do
|
10
|
+
-# Missing Info
|
11
|
+
- if EffectiveResources.authorized?(self, :resubmit, resource)
|
12
|
+
= f.save 'Submit Application'
|
13
|
+
- else
|
14
|
+
= f.save 'Save and Continue'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
subject: 'Your application was marked as completed!'
|
3
|
+
from: 'admin@example.com'
|
4
|
+
---
|
5
|
+
Hello {{ user.name }},
|
6
|
+
|
7
|
+
Your application for {{ applicant.to_category }} has been marked completed.
|
8
|
+
|
9
|
+
It is ready for review and a final decision to approve or decline.
|
10
|
+
|
11
|
+
{{ applicant.url }}
|
12
|
+
|
13
|
+
Thank you.
|
14
|
+
|
15
|
+
Please contact us for assistance.
|
@@ -0,0 +1,17 @@
|
|
1
|
+
---
|
2
|
+
subject: 'Your application is missing information'
|
3
|
+
from: 'admin@example.com'
|
4
|
+
---
|
5
|
+
Hello {{ user.name }},
|
6
|
+
|
7
|
+
Your application for {{ applicant.to_category }} is missing information:
|
8
|
+
|
9
|
+
{{ applicant.missing_info_reason }}
|
10
|
+
|
11
|
+
Please update your application with this info.
|
12
|
+
|
13
|
+
{{ applicant.url }}
|
14
|
+
|
15
|
+
Thank you.
|
16
|
+
|
17
|
+
Please contact us for assistance.
|
@@ -21,6 +21,11 @@ EffectiveMemberships.setup do |config|
|
|
21
21
|
# The defaults include: Applicant, Prorated, Renewal, Late, Admin
|
22
22
|
# config.additional_fee_types = []
|
23
23
|
|
24
|
+
# Applicant Reviews
|
25
|
+
# When true, display the reviewed state and require Category.min_applicant_reviews
|
26
|
+
# When false, hide the reviewed state entirely
|
27
|
+
# config.applicant_reviews = false
|
28
|
+
|
24
29
|
# Mailer Configuration
|
25
30
|
# Configure the class responsible to send e-mails.
|
26
31
|
# config.mailer = 'Effective::MembershipsMailer'
|
@@ -151,6 +151,10 @@ class CreateEffectiveMemberships < ActiveRecord::Migration[6.0]
|
|
151
151
|
t.datetime :declined_at
|
152
152
|
t.text :declined_reason
|
153
153
|
|
154
|
+
# Missing
|
155
|
+
t.datetime :missing_info_at
|
156
|
+
t.text :missing_info_reason
|
157
|
+
|
154
158
|
# Applicant Educations
|
155
159
|
t.text :applicant_educations_details
|
156
160
|
|
@@ -8,7 +8,7 @@ module EffectiveMemberships
|
|
8
8
|
[
|
9
9
|
:categories_table_name, :applicants_table_name, :applicant_reviews_table_name, :fee_payments_table_name,
|
10
10
|
:category_class_name, :applicant_class_name, :applicant_review_class_name, :fee_payment_class_name, :registrar_class_name, :membership_card_class_name,
|
11
|
-
:additional_fee_types,
|
11
|
+
:additional_fee_types, :applicant_reviews,
|
12
12
|
:layout,
|
13
13
|
:mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_admin, :use_effective_email_templates
|
14
14
|
]
|
@@ -36,6 +36,10 @@ module EffectiveMemberships
|
|
36
36
|
membership_card_class_name&.constantize || Effective::MembershipCard
|
37
37
|
end
|
38
38
|
|
39
|
+
def self.applicant_reviews?
|
40
|
+
applicant_reviews == true
|
41
|
+
end
|
42
|
+
|
39
43
|
# Singleton
|
40
44
|
def self.Registrar
|
41
45
|
klass = registrar_class_name&.constantize || Effective::Registrar
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_memberships
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-02
|
11
|
+
date: 2022-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -317,7 +317,9 @@ files:
|
|
317
317
|
- app/views/admin/applicant_references/_applicant_reference.html.haml
|
318
318
|
- app/views/admin/applicants/_form.html.haml
|
319
319
|
- app/views/admin/applicants/_form_approve.html.haml
|
320
|
+
- app/views/admin/applicants/_form_complete.html.haml
|
320
321
|
- app/views/admin/applicants/_form_decline.html.haml
|
322
|
+
- app/views/admin/applicants/_form_missing_info.html.haml
|
321
323
|
- app/views/admin/applicants/_form_process.html.haml
|
322
324
|
- app/views/admin/applicants/_status.html.haml
|
323
325
|
- app/views/admin/categories/_form.html.haml
|
@@ -360,6 +362,7 @@ files:
|
|
360
362
|
- app/views/effective/applicants/_experience.html.haml
|
361
363
|
- app/views/effective/applicants/_files.html.haml
|
362
364
|
- app/views/effective/applicants/_layout.html.haml
|
365
|
+
- app/views/effective/applicants/_missing_info.html.haml
|
363
366
|
- app/views/effective/applicants/_orders.html.haml
|
364
367
|
- app/views/effective/applicants/_references.html.haml
|
365
368
|
- app/views/effective/applicants/_select.html.haml
|
@@ -403,7 +406,9 @@ files:
|
|
403
406
|
- app/views/effective/memberships/_membership.html.haml
|
404
407
|
- app/views/effective/memberships_directory/index.html.haml
|
405
408
|
- app/views/effective/memberships_mailer/applicant_approved.liquid
|
409
|
+
- app/views/effective/memberships_mailer/applicant_completed.liquid
|
406
410
|
- app/views/effective/memberships_mailer/applicant_declined.liquid
|
411
|
+
- app/views/effective/memberships_mailer/applicant_missing_info.liquid
|
407
412
|
- app/views/effective/memberships_mailer/applicant_reference_notification.liquid
|
408
413
|
- app/views/layouts/effective_memberships_mailer_layout.html.haml
|
409
414
|
- config/effective_memberships.rb
|