effective_memberships 0.6.13 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/admin/applicant_reviews_controller.rb +19 -0
- data/app/controllers/effective/applicant_reviews_controller.rb +13 -0
- data/app/datatables/admin/effective_applicant_reviews_datatable.rb +24 -0
- data/app/datatables/effective_applicant_reviews_datatable.rb +25 -0
- data/app/datatables/effective_available_applicant_reviews_datatable.rb +40 -0
- data/app/mailers/effective/memberships_mailer.rb +43 -0
- data/app/models/concerns/effective_memberships_applicant.rb +23 -2
- data/app/models/concerns/effective_memberships_applicant_review.rb +34 -68
- data/app/models/concerns/effective_memberships_user.rb +6 -0
- data/app/views/admin/applicant_reviews/_applicant_review.html.haml +1 -0
- data/app/views/admin/applicants/_form_applicant.html.haml +4 -0
- data/app/views/admin/applicants/_status.html.haml +2 -2
- data/app/views/effective/applicant_reviews/_applicant_review.html.haml +4 -0
- data/app/views/effective/applicant_reviews/_content.html.haml +8 -0
- data/app/views/effective/applicant_reviews/_dashboard.html.haml +36 -0
- data/app/views/effective/applicant_reviews/_layout.html.haml +3 -0
- data/app/views/effective/applicant_reviews/_recommendation.html.haml +23 -0
- data/app/views/effective/applicant_reviews/_review.html.haml +1 -0
- data/app/views/effective/applicant_reviews/recommendation.html.haml +20 -0
- data/app/views/effective/applicant_reviews/review.html.haml +14 -0
- data/app/views/effective/applicant_reviews/start.html.haml +18 -0
- data/app/views/effective/applicant_reviews/submitted.html.haml +15 -0
- data/app/views/effective/applicants/_summary.html.haml +4 -3
- data/app/views/effective/memberships_mailer/applicant_review_submitted.liquid +19 -0
- data/config/routes.rb +6 -0
- data/lib/effective_memberships/version.rb +1 -1
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3972d4221b4931ed7f157f87ef8a7d9c9a1ad785679599a13c3d38e37fd48e56
|
4
|
+
data.tar.gz: 4a19e5c29db9c7ee41fd67177cda71197adb743f1f4eaaf97116192af82c562b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b5b013d0f0c7eddfbef6ed4b75c93169bfd4a48eebb07af26bb768d39f57285efb725266b26f6a75f05b14657ddb1ba9490594568b0deb65126caef3b873f99
|
7
|
+
data.tar.gz: cd37dded19f0ef05190120efe7749a6c0c3e71c5c53b53690c5d5e7e234a8b2b00e12db26480ee3e9f49617c505ca52499254d37b4ebd03c7e0918866e7af6d4
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Admin
|
2
|
+
class ApplicantReviewsController < ApplicationController
|
3
|
+
before_action(:authenticate_user!) if defined?(Devise)
|
4
|
+
before_action { EffectiveResources.authorize!(self, :admin, :effective_memberships) }
|
5
|
+
|
6
|
+
include Effective::CrudController
|
7
|
+
|
8
|
+
resource_scope -> { EffectiveMemberships.ApplicantReview.deep.all }
|
9
|
+
datatable -> { Admin::EffectiveApplicantReviewsDatatable.new }
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def permitted_params
|
14
|
+
model = (params.key?(:effective_applicant_review) ? :effective_applicant_review: :applicant_review)
|
15
|
+
params.require(model).permit!
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Effective
|
2
|
+
class ApplicantReviewsController < ApplicationController
|
3
|
+
before_action(:authenticate_user!) if defined?(Devise)
|
4
|
+
|
5
|
+
include Effective::WizardController
|
6
|
+
|
7
|
+
resource_scope -> {
|
8
|
+
applicant = EffectiveMemberships.Applicant.find(params[:applicant_id])
|
9
|
+
EffectiveMemberships.ApplicantReview.deep.where(reviewer: current_user, applicant: applicant)
|
10
|
+
}
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Admin
|
2
|
+
class EffectiveApplicantReviewsDatatable < Effective::Datatable
|
3
|
+
datatable do
|
4
|
+
order :submitted_at
|
5
|
+
|
6
|
+
col :created_at, visible: false
|
7
|
+
col :id, visible: false
|
8
|
+
|
9
|
+
col :submitted_at, label: 'Reviewed', as: :date
|
10
|
+
col :reviewer
|
11
|
+
col :applicant
|
12
|
+
|
13
|
+
col :recommendation
|
14
|
+
col :comments
|
15
|
+
|
16
|
+
actions_col
|
17
|
+
end
|
18
|
+
|
19
|
+
collection do
|
20
|
+
EffectiveMemberships.ApplicantReview.deep.submitted
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# Dashboard ApplicantReviews
|
2
|
+
class EffectiveApplicantReviewsDatatable < Effective::Datatable
|
3
|
+
datatable do
|
4
|
+
order :id, :desc
|
5
|
+
|
6
|
+
col :created_at, visible: false
|
7
|
+
col :id, visible: false
|
8
|
+
|
9
|
+
col :applicant
|
10
|
+
col :reviewer, visible: false
|
11
|
+
|
12
|
+
col :submitted_at, label: 'Reviewed', as: :date
|
13
|
+
col :recommendation
|
14
|
+
col :comments
|
15
|
+
|
16
|
+
actions_col(show: false) do |applicant_review|
|
17
|
+
dropdown_link_to('Show', effective_memberships.applicant_applicant_review_path(applicant_review.applicant, applicant_review))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
collection do
|
22
|
+
EffectiveMemberships.ApplicantReview.deep.submitted.where(reviewer: current_user)
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# Dashboard Available Applicant Reviews
|
2
|
+
class EffectiveAvailableApplicantReviewsDatatable < Effective::Datatable
|
3
|
+
datatable do
|
4
|
+
order :created_at
|
5
|
+
|
6
|
+
col :id, visible: false
|
7
|
+
|
8
|
+
col :created_at, label: 'Created', as: :date, visible: false
|
9
|
+
col :updated_at, label: 'Updated', as: :date, visible: false
|
10
|
+
col :submitted_at, label: 'Submitted', as: :date, visible: false
|
11
|
+
|
12
|
+
# This is when they become available for review
|
13
|
+
col :completed_at, label: 'Date', as: :date
|
14
|
+
|
15
|
+
col :user
|
16
|
+
col :category, label: 'Category'
|
17
|
+
col :to_status, label: 'Status'
|
18
|
+
|
19
|
+
actions_col(show: false) do |applicant|
|
20
|
+
applicant_review = applicant.applicant_review(reviewer: current_user)
|
21
|
+
|
22
|
+
if applicant_review.blank?
|
23
|
+
dropdown_link_to('Start Review', effective_memberships.new_applicant_applicant_review_path(applicant), 'data-turbolinks' => false)
|
24
|
+
elsif applicant_review.in_progress?
|
25
|
+
dropdown_link_to('Continue', effective_memberships.applicant_applicant_review_build_path(applicant, applicant_review, applicant_review.next_step), 'data-turbolinks' => false)
|
26
|
+
dropdown_link_to('Delete', effective_memberships.applicant_applicant_review_path(applicant, applicant_review), 'data-confirm': "Really delete #{applicant_review}?", 'data-method': :delete)
|
27
|
+
else
|
28
|
+
dropdown_link_to('Show', effective_memberships.applicant_applicant_review_path(applicant, applicant_review), 'data-turbolinks' => false)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
collection do
|
34
|
+
# These ones have already been submitted by this reviewer
|
35
|
+
submitted = EffectiveMemberships.ApplicantReview.deep.submitted.where(reviewer: current_user).select('applicant_id')
|
36
|
+
|
37
|
+
EffectiveMemberships.Applicant.deep.reviewable.where.not(id: submitted)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -64,6 +64,17 @@ module Effective
|
|
64
64
|
mail(to: resource.email, subject: subject, **headers)
|
65
65
|
end
|
66
66
|
|
67
|
+
def applicant_review_submitted(resource, opts = {})
|
68
|
+
@assigns = assigns_for(resource)
|
69
|
+
@applicant_review = resource
|
70
|
+
@applicant = resource.applicant
|
71
|
+
|
72
|
+
subject = subject_for(__method__, "Applicant Review for #{resource.applicant} submitted", resource, opts)
|
73
|
+
headers = headers_for(resource, opts)
|
74
|
+
|
75
|
+
mail(to: mailer_admin, subject: subject, **headers)
|
76
|
+
end
|
77
|
+
|
67
78
|
protected
|
68
79
|
|
69
80
|
def assigns_for(resource)
|
@@ -71,6 +82,10 @@ module Effective
|
|
71
82
|
return applicant_assigns(resource).merge(owner_assigns(resource.owner)).merge(membership_assigns(resource.owner.membership))
|
72
83
|
end
|
73
84
|
|
85
|
+
if resource.class.respond_to?(:effective_memberships_applicant_review?)
|
86
|
+
return applicant_review_assigns(resource).merge(applicant_assigns(resource.applicant)).merge(owner_assigns(resource.applicant.owner)).merge(membership_assigns(resource.applicant.owner.membership))
|
87
|
+
end
|
88
|
+
|
74
89
|
if resource.kind_of?(Effective::ApplicantEndorsement)
|
75
90
|
return endorsement_assigns(resource).merge(owner_assigns(resource.applicant.owner))
|
76
91
|
end
|
@@ -103,6 +118,23 @@ module Effective
|
|
103
118
|
{ applicant: values }
|
104
119
|
end
|
105
120
|
|
121
|
+
def applicant_review_assigns(applicant_review)
|
122
|
+
raise('expected an applicant review') unless applicant_review.class.respond_to?(:effective_memberships_applicant_review?)
|
123
|
+
|
124
|
+
values = {
|
125
|
+
date: (applicant_review.submitted_at || Time.zone.now).strftime('%F'),
|
126
|
+
submitted_at: (applicant_review.submitted_at&.strftime('%F') || 'not submitted'),
|
127
|
+
|
128
|
+
url: effective_memberships.applicant_applicant_review_url(applicant_review.applicant, applicant_review),
|
129
|
+
admin_url: effective_memberships.admin_applicant_review_url(applicant_review),
|
130
|
+
|
131
|
+
recommendation: applicant_review.recommendation.presence,
|
132
|
+
comments: applicant_review.comments.presence
|
133
|
+
}.compact
|
134
|
+
|
135
|
+
{ applicant_review: values }
|
136
|
+
end
|
137
|
+
|
106
138
|
def membership_assigns(membership)
|
107
139
|
return {} if membership.blank?
|
108
140
|
raise('expected a membership') unless membership.kind_of?(Effective::Membership)
|
@@ -149,5 +181,16 @@ module Effective
|
|
149
181
|
{ user: values }
|
150
182
|
end
|
151
183
|
|
184
|
+
def reviewer_assigns(owner)
|
185
|
+
raise('expected a owner') unless owner.class.respond_to?(:effective_memberships_owner?)
|
186
|
+
|
187
|
+
values = {
|
188
|
+
name: owner.to_s,
|
189
|
+
email: owner.email
|
190
|
+
}
|
191
|
+
|
192
|
+
{ reviewer: values }
|
193
|
+
end
|
194
|
+
|
152
195
|
end
|
153
196
|
end
|
@@ -187,6 +187,8 @@ module EffectiveMembershipsApplicant
|
|
187
187
|
|
188
188
|
scope :not_draft, -> { where.not(status: :draft) }
|
189
189
|
|
190
|
+
scope :reviewable, -> { where(status: :completed) }
|
191
|
+
|
190
192
|
scope :for, -> (user) {
|
191
193
|
raise('expected a effective memberships user') unless user.class.try(:effective_memberships_user?)
|
192
194
|
where(user: user).or(where(organization: user.organizations))
|
@@ -750,6 +752,10 @@ module EffectiveMembershipsApplicant
|
|
750
752
|
end
|
751
753
|
|
752
754
|
# Completed -> Reviewed requirements
|
755
|
+
def reviewable?
|
756
|
+
completed?
|
757
|
+
end
|
758
|
+
|
753
759
|
def applicant_reviews_required?
|
754
760
|
(min_applicant_reviews > 0 || applicant_reviews.present?)
|
755
761
|
end
|
@@ -758,6 +764,16 @@ module EffectiveMembershipsApplicant
|
|
758
764
|
category&.min_applicant_reviews.to_i
|
759
765
|
end
|
760
766
|
|
767
|
+
# Find
|
768
|
+
def applicant_review(reviewer:)
|
769
|
+
applicant_reviews.find { |ar| ar.reviewer_id == reviewer.id && ar.reviewer_type == reviewer.class.name }
|
770
|
+
end
|
771
|
+
|
772
|
+
# Find or build
|
773
|
+
def build_applicant_review(reviewer:)
|
774
|
+
applicant_review(reviewer: reviewer) || applicant_reviews.build(reviewer: reviewer)
|
775
|
+
end
|
776
|
+
|
761
777
|
# When an application is completed, these must be done to go to reviewed
|
762
778
|
# An Admin can override this and just set them to reviewed.
|
763
779
|
def reviewed_requirements
|
@@ -765,17 +781,22 @@ module EffectiveMembershipsApplicant
|
|
765
781
|
return requirements unless category.present?
|
766
782
|
|
767
783
|
if applicant_reviews_required?
|
768
|
-
requirements['Applicant Reviews'] = (applicant_reviews.count(&:
|
784
|
+
requirements['Applicant Reviews'] = (applicant_reviews.count(&:done?) >= min_applicant_reviews)
|
769
785
|
end
|
770
786
|
|
771
787
|
requirements
|
772
788
|
end
|
773
789
|
|
790
|
+
# Called when an applicant_review was submitted
|
791
|
+
def try_reviewed!
|
792
|
+
return false unless completed? && reviewed_requirements.values.all?
|
793
|
+
reviewed!
|
794
|
+
end
|
795
|
+
|
774
796
|
def review!
|
775
797
|
raise('applicant must have been submitted to review!') unless was_submitted?
|
776
798
|
|
777
799
|
# Let an admin ignore these requirements if need be
|
778
|
-
# return false unless completed? && reviewed_requirements.values.all?
|
779
800
|
reviewed!
|
780
801
|
end
|
781
802
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# EffectiveMembershipsApplicantReview
|
4
4
|
#
|
5
|
-
# Mark your
|
5
|
+
# Mark your owner model with effective_memberships_applicant_review to get all the includes
|
6
6
|
|
7
7
|
module EffectiveMembershipsApplicantReview
|
8
8
|
extend ActiveSupport::Concern
|
@@ -22,82 +22,60 @@ module EffectiveMembershipsApplicantReview
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def recommendations
|
25
|
-
['
|
25
|
+
['Recommend Approve', 'Recommend Decline', 'Missing Information']
|
26
26
|
end
|
27
27
|
|
28
28
|
end
|
29
29
|
|
30
30
|
included do
|
31
|
-
log_changes if respond_to?(:log_changes)
|
31
|
+
log_changes(to: :applicant) if respond_to?(:log_changes)
|
32
32
|
|
33
33
|
acts_as_tokened
|
34
34
|
|
35
35
|
acts_as_statused(
|
36
|
-
:draft,
|
37
|
-
:
|
38
|
-
:accepted, # Accepted
|
39
|
-
:rejected # Rejected
|
36
|
+
:draft, # Just Started
|
37
|
+
:submitted # All Done
|
40
38
|
)
|
41
39
|
|
42
40
|
acts_as_wizard(
|
43
41
|
start: 'Start',
|
44
|
-
|
45
|
-
education: 'Education',
|
46
|
-
course_amounts: 'Courses',
|
47
|
-
experience: 'Work Experience',
|
48
|
-
references: 'References',
|
49
|
-
files: 'Attach Files',
|
50
|
-
declarations: 'Declarations',
|
42
|
+
review: 'Review Applicant',
|
51
43
|
recommendation: 'Recommendation',
|
52
44
|
submitted: 'Submitted'
|
53
45
|
)
|
54
46
|
|
47
|
+
scope :in_progress, -> { where(status: :draft) }
|
48
|
+
scope :done, -> { where(status: :submitted) }
|
49
|
+
|
55
50
|
belongs_to :applicant
|
56
51
|
belongs_to :reviewer, polymorphic: true
|
57
52
|
|
58
53
|
effective_resource do
|
59
54
|
submitted_at :datetime
|
60
|
-
recommendation :string
|
61
55
|
|
56
|
+
recommendation :string
|
62
57
|
comments :text # Rolling comments
|
63
58
|
|
64
|
-
# Conflict Step
|
65
|
-
conflict_of_interest :boolean
|
66
|
-
|
67
|
-
# Education Step
|
68
|
-
education_accepted :boolean
|
69
|
-
|
70
|
-
# Course Amounts
|
71
|
-
course_amounts_accepted :boolean
|
72
|
-
|
73
|
-
# Courses
|
74
|
-
courses_accepted :boolean
|
75
|
-
|
76
|
-
# Experience Step
|
77
|
-
experience_accepted :boolean
|
78
|
-
|
79
|
-
# References Step
|
80
|
-
references_accepted :boolean
|
81
|
-
|
82
|
-
# References Step
|
83
|
-
files_accepted :boolean
|
84
|
-
|
85
59
|
timestamps
|
86
60
|
end
|
87
61
|
|
88
|
-
scope :deep, -> { includes(:reviewer, applicant: :
|
62
|
+
scope :deep, -> { includes(:reviewer, applicant: :user) }
|
89
63
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
64
|
+
scope :for, -> (user) {
|
65
|
+
raise('expected a effective memberships user') unless user.class.try(:effective_memberships_user?)
|
66
|
+
where(reviewer: user)
|
67
|
+
}
|
94
68
|
|
95
|
-
|
69
|
+
with_options(if: -> { submitted? }) do
|
70
|
+
validates :recommendation, presence: true
|
96
71
|
|
97
|
-
|
72
|
+
validate do
|
73
|
+
self.errors.add(:recommendation, 'is invalid') unless EffectiveMemberships.ApplicantReview.recommendations.include?(recommendation)
|
74
|
+
end
|
75
|
+
end
|
98
76
|
|
99
77
|
def to_s
|
100
|
-
|
78
|
+
"Review of #{applicant}"
|
101
79
|
end
|
102
80
|
|
103
81
|
def in_progress?
|
@@ -105,43 +83,31 @@ module EffectiveMembershipsApplicantReview
|
|
105
83
|
end
|
106
84
|
|
107
85
|
def done?
|
108
|
-
|
86
|
+
submitted?
|
109
87
|
end
|
110
88
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
applicant.save!
|
116
|
-
|
117
|
-
after_commit { send_email(:applicant_review_conflict_of_interest) }
|
118
|
-
true
|
89
|
+
def can_visit_step?(step)
|
90
|
+
return (step == :submitted) if was_submitted?
|
91
|
+
can_revisit_completed_steps(step)
|
119
92
|
end
|
120
93
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
applicant.save!
|
126
|
-
|
127
|
-
after_commit { send_email(:applicant_review_completed) }
|
128
|
-
true
|
94
|
+
# Called by the recommendation wizard step
|
95
|
+
def recommendation!
|
96
|
+
submit!
|
129
97
|
end
|
130
98
|
|
131
|
-
def
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
applicant.save!
|
99
|
+
def submit!
|
100
|
+
submitted!
|
101
|
+
applicant.try_reviewed!
|
136
102
|
|
137
|
-
after_commit { send_email(:
|
103
|
+
after_commit { send_email(:applicant_review_submitted) }
|
138
104
|
true
|
139
105
|
end
|
140
106
|
|
141
107
|
private
|
142
108
|
|
143
109
|
def send_email(email)
|
144
|
-
EffectiveMemberships.send_email(email, self
|
110
|
+
EffectiveMemberships.send_email(email, self)
|
145
111
|
end
|
146
112
|
|
147
113
|
end
|
@@ -21,6 +21,7 @@ module EffectiveMembershipsUser
|
|
21
21
|
# App scoped
|
22
22
|
has_many :applicants, -> { order(:id) }, inverse_of: :user, as: :user
|
23
23
|
has_many :fee_payments, -> { order(:id) }, inverse_of: :user, as: :user
|
24
|
+
has_many :applicant_reviews, -> { order(:id) }, inverse_of: :reviewer, as: :reviewer
|
24
25
|
|
25
26
|
# Effective Scoped
|
26
27
|
has_many :representatives, -> { Effective::Representative.sorted },
|
@@ -85,4 +86,9 @@ module EffectiveMembershipsUser
|
|
85
86
|
membership_history_on(date).try(:membership_categories)
|
86
87
|
end
|
87
88
|
|
89
|
+
# Roles
|
90
|
+
def applicant_reviewer?
|
91
|
+
false
|
92
|
+
end
|
93
|
+
|
88
94
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'effective/applicant_reviews/applicant_review', applicant_review: applicant_review
|
@@ -17,6 +17,10 @@
|
|
17
17
|
= render 'effective/applicants/applicant', applicant: applicant, namespace: :admin
|
18
18
|
|
19
19
|
- # Just normal tabs now
|
20
|
+
- if applicant.applicant_reviews.present?
|
21
|
+
= tab 'Reviews' do
|
22
|
+
.mb-4= render_inline_datatable(Admin::EffectiveApplicantReviewsDatatable.new(applicant: applicant))
|
23
|
+
|
20
24
|
- if applicant.was_submitted? && !applicant.was_approved?
|
21
25
|
= tab 'Process' do
|
22
26
|
= render 'admin/applicants/form_process', applicant: applicant
|
@@ -107,10 +107,10 @@
|
|
107
107
|
- if applicant.reviewed_requirements['Applicant Reviews']
|
108
108
|
= icon('check', class: 'small-1')
|
109
109
|
|
110
|
-
= applicant.applicant_reviews.count(&:
|
110
|
+
= applicant.applicant_reviews.count(&:submitted?)
|
111
111
|
= '/'
|
112
112
|
= applicant.min_applicant_reviews
|
113
|
-
Reviews
|
113
|
+
Reviews Submitted
|
114
114
|
- else
|
115
115
|
%p
|
116
116
|
= icon('check', class: 'small-1')
|
@@ -0,0 +1,8 @@
|
|
1
|
+
- all_steps_content = resource.applicant&.category&.rich_text_applicant_review_all_steps_content
|
2
|
+
- step_content = resource.applicant&.category&.send("rich_text_applicant_review_#{step}_content")
|
3
|
+
|
4
|
+
- if all_steps_content.present?
|
5
|
+
.mb-2= all_steps_content
|
6
|
+
|
7
|
+
- if step_content.present?
|
8
|
+
.mb-2= step_content
|
@@ -0,0 +1,36 @@
|
|
1
|
+
- authorized = EffectiveResources.authorized?(self, :new, EffectiveMemberships.ApplicantReview)
|
2
|
+
|
3
|
+
- available = EffectiveResources.best('EffectiveAvailableApplicantReviewsDatatable').new(self)
|
4
|
+
- datatable = EffectiveResources.best('EffectiveApplicantReviewsDatatable').new(self)
|
5
|
+
|
6
|
+
- # In progress
|
7
|
+
- applicant_review = current_user.applicant_reviews.in_progress.first
|
8
|
+
|
9
|
+
- if applicant_review.present? && applicant_review.draft?
|
10
|
+
%h2 In-Progress Applicant Review
|
11
|
+
|
12
|
+
%p
|
13
|
+
Your review of #{applicant_review} is incomplete.
|
14
|
+
|
15
|
+
%p
|
16
|
+
Please
|
17
|
+
= link_to("Continue review", effective_memberships.applicant_applicant_review_build_path(applicant_review.applicant, applicant_review, applicant_review.next_step), 'data-turbolinks' => false, class: 'btn btn-primary')
|
18
|
+
or you can
|
19
|
+
= link_to('Abandon review', effective_memberships.applicant_applicant_review_path(applicant_review.applicant, applicant_review), 'data-confirm': "Really delete #{applicant_review}?", 'data-method': :delete, class: 'btn btn-danger')
|
20
|
+
to review again.
|
21
|
+
|
22
|
+
%hr
|
23
|
+
|
24
|
+
%h2 Applicant Reviews
|
25
|
+
|
26
|
+
- if available.present?
|
27
|
+
%p The following applicants are available for your review:
|
28
|
+
|
29
|
+
= render_simple_datatable(available)
|
30
|
+
- else
|
31
|
+
%p There are no applicants available for your review. When there are, we'll show them here.
|
32
|
+
|
33
|
+
- if datatable.present?
|
34
|
+
.mt-4
|
35
|
+
%h2 Review History
|
36
|
+
= render_datatable(datatable, simple: true)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
= wizard_card(applicant_review) do
|
2
|
+
%table.table
|
3
|
+
- if request.path.start_with?('/admin')
|
4
|
+
%tr
|
5
|
+
%th Reviewer
|
6
|
+
%td
|
7
|
+
- url = (polymorphic_admin_path(applicant_review.reviewer) rescue "/admin/users/#{applicant_review.reviewer.to_param}/edit")
|
8
|
+
= link_to(applicant_review.reviewer, url)
|
9
|
+
- else
|
10
|
+
%tr
|
11
|
+
%th Reviewer
|
12
|
+
%td
|
13
|
+
= applicant_review.reviewer.to_s
|
14
|
+
%br
|
15
|
+
= mail_to(applicant_review.reviewer.email)
|
16
|
+
|
17
|
+
%tr
|
18
|
+
%th Recommendation
|
19
|
+
%td= applicant_review.recommendation
|
20
|
+
|
21
|
+
%tr
|
22
|
+
%th Comments
|
23
|
+
%td= simple_format(applicant_review.comments.presence || 'none')
|
@@ -0,0 +1 @@
|
|
1
|
+
- # Intentionally blank
|
@@ -0,0 +1,20 @@
|
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/applicant_reviews/content', resource: resource
|
3
|
+
|
4
|
+
= card('Summary') do
|
5
|
+
= render 'effective/applicants/summary', applicant: resource.applicant
|
6
|
+
|
7
|
+
.mb-2
|
8
|
+
= collapse('Show application...', card_class: 'my-2') do
|
9
|
+
= render 'effective/applicants/applicant', applicant: resource.applicant
|
10
|
+
|
11
|
+
= card('Recommendation') do
|
12
|
+
|
13
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
14
|
+
= f.hidden_field :id
|
15
|
+
|
16
|
+
%p My recommendation is
|
17
|
+
= f.radios :recommendation, EffectiveMemberships.ApplicantReview.recommendations, label: false
|
18
|
+
= f.text_area :comments, label: 'Reviewer comments'
|
19
|
+
|
20
|
+
= f.save 'Submit Recommendation'
|
@@ -0,0 +1,14 @@
|
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/applicant_reviews/content', resource: resource
|
3
|
+
|
4
|
+
= card do
|
5
|
+
= render 'effective/applicants/summary', applicant: resource.applicant
|
6
|
+
= render 'effective/applicants/applicant', applicant: resource.applicant
|
7
|
+
|
8
|
+
= card do
|
9
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
10
|
+
= f.hidden_field :id
|
11
|
+
|
12
|
+
= f.text_area :comments, label: 'Reviewer comments'
|
13
|
+
|
14
|
+
= f.save 'Save and Continue'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/applicant_reviews/content', resource: resource
|
3
|
+
|
4
|
+
= card do
|
5
|
+
%p Welcome #{current_user}!
|
6
|
+
|
7
|
+
%p You are starting an applicant review for #{resource.applicant}.
|
8
|
+
|
9
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
10
|
+
= f.hidden_field :id
|
11
|
+
|
12
|
+
= f.hidden_field :applicant_type, value: f.object.applicant.class.name
|
13
|
+
= f.hidden_field :applicant_id
|
14
|
+
|
15
|
+
= f.hidden_field :reviewer_type
|
16
|
+
= f.hidden_field :reviewer_id
|
17
|
+
|
18
|
+
= f.save 'Save and Continue'
|
@@ -0,0 +1,15 @@
|
|
1
|
+
= render 'layout' do
|
2
|
+
= render 'effective/applicant_reviews/content', resource: resource
|
3
|
+
|
4
|
+
- raise('expected a submitted applicant review') unless resource.was_submitted?
|
5
|
+
|
6
|
+
.alert.alert-success.mb-4
|
7
|
+
This review was submitted on #{resource.submitted_at.strftime('%F')}
|
8
|
+
|
9
|
+
.mb-4
|
10
|
+
= collapse('Show application...', card_class: 'my-2') do
|
11
|
+
= render 'effective/applicants/applicant', applicant: resource.applicant
|
12
|
+
|
13
|
+
= render 'effective/applicant_reviews/applicant_review', applicant_review: resource
|
14
|
+
|
15
|
+
= link_to "Return to Dashboard", root_path, class: 'btn btn-lg btn-primary btn-block'
|
@@ -54,11 +54,12 @@
|
|
54
54
|
%th Stream
|
55
55
|
%td= applicant.stream
|
56
56
|
|
57
|
-
-
|
57
|
+
- orders = applicant.orders.select { |order| EffectiveResources.authorized?(self, :show, order) }
|
58
|
+
- if orders.present?
|
58
59
|
%tr
|
59
|
-
%th Order#{'s' if
|
60
|
+
%th Order#{'s' if orders.length > 1}
|
60
61
|
%td
|
61
|
-
-
|
62
|
+
- orders.each do |order|
|
62
63
|
- if request.path.start_with?('/admin')
|
63
64
|
= link_to(order, effective_orders.edit_admin_order_path(order))
|
64
65
|
- else
|
@@ -0,0 +1,19 @@
|
|
1
|
+
---
|
2
|
+
subject: 'An applicant review has been submitted'
|
3
|
+
from: 'admin@example.com'
|
4
|
+
---
|
5
|
+
Hello admin,
|
6
|
+
|
7
|
+
The application for {{ user.name }} for {{ applicant.to_category }} has been reviewed by #{{ reviewer.name }}
|
8
|
+
|
9
|
+
They recommended {{ applicant_review.recommendation }} with the following comments:
|
10
|
+
|
11
|
+
{{ applicant_review.comments }}
|
12
|
+
|
13
|
+
For more details please visit
|
14
|
+
|
15
|
+
{{ applicant.admin_url }}
|
16
|
+
|
17
|
+
Thanks,
|
18
|
+
|
19
|
+
Have a great day!
|
data/config/routes.rb
CHANGED
@@ -7,6 +7,10 @@ EffectiveMemberships::Engine.routes.draw do
|
|
7
7
|
scope module: 'effective' do
|
8
8
|
resources :applicants, only: [:new, :show, :destroy] do
|
9
9
|
resources :build, controller: :applicants, only: [:show, :update]
|
10
|
+
|
11
|
+
resources :applicant_reviews, only: [:new, :show, :destroy] do
|
12
|
+
resources :build, controller: :applicant_reviews, only: [:show, :update]
|
13
|
+
end
|
10
14
|
end
|
11
15
|
|
12
16
|
resources :applicant_endorsements, only: [:new, :create, :show, :update] do
|
@@ -45,6 +49,8 @@ EffectiveMemberships::Engine.routes.draw do
|
|
45
49
|
post :notify, on: :member
|
46
50
|
end
|
47
51
|
|
52
|
+
resources :applicant_reviews, only: [:index, :show]
|
53
|
+
|
48
54
|
resources :fees
|
49
55
|
resources :categories, only: [:index, :edit, :update]
|
50
56
|
|
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.
|
4
|
+
version: 0.7.0
|
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-09-
|
11
|
+
date: 2022-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -258,6 +258,7 @@ files:
|
|
258
258
|
- app/controllers/admin/applicant_course_names_controller.rb
|
259
259
|
- app/controllers/admin/applicant_endorsements_controller.rb
|
260
260
|
- app/controllers/admin/applicant_references_controller.rb
|
261
|
+
- app/controllers/admin/applicant_reviews_controller.rb
|
261
262
|
- app/controllers/admin/applicants_controller.rb
|
262
263
|
- app/controllers/admin/categories_controller.rb
|
263
264
|
- app/controllers/admin/fee_payments_controller.rb
|
@@ -270,6 +271,7 @@ files:
|
|
270
271
|
- app/controllers/admin/statuses_controller.rb
|
271
272
|
- app/controllers/effective/applicant_endorsements_controller.rb
|
272
273
|
- app/controllers/effective/applicant_references_controller.rb
|
274
|
+
- app/controllers/effective/applicant_reviews_controller.rb
|
273
275
|
- app/controllers/effective/applicants_controller.rb
|
274
276
|
- app/controllers/effective/fee_payments_controller.rb
|
275
277
|
- app/controllers/effective/membership_cards_controller.rb
|
@@ -280,6 +282,7 @@ files:
|
|
280
282
|
- app/datatables/admin/effective_applicant_course_names_datatable.rb
|
281
283
|
- app/datatables/admin/effective_applicant_endorsements_datatable.rb
|
282
284
|
- app/datatables/admin/effective_applicant_references_datatable.rb
|
285
|
+
- app/datatables/admin/effective_applicant_reviews_datatable.rb
|
283
286
|
- app/datatables/admin/effective_applicants_datatable.rb
|
284
287
|
- app/datatables/admin/effective_categories_datatable.rb
|
285
288
|
- app/datatables/admin/effective_fee_payments_datatable.rb
|
@@ -296,7 +299,9 @@ files:
|
|
296
299
|
- app/datatables/effective_applicant_equivalences_datatable.rb
|
297
300
|
- app/datatables/effective_applicant_experiences_datatable.rb
|
298
301
|
- app/datatables/effective_applicant_references_datatable.rb
|
302
|
+
- app/datatables/effective_applicant_reviews_datatable.rb
|
299
303
|
- app/datatables/effective_applicants_datatable.rb
|
304
|
+
- app/datatables/effective_available_applicant_reviews_datatable.rb
|
300
305
|
- app/datatables/effective_fee_payments_datatable.rb
|
301
306
|
- app/datatables/effective_memberships_directory_datatable.rb
|
302
307
|
- app/datatables/effective_organizations_datatable.rb
|
@@ -342,6 +347,7 @@ files:
|
|
342
347
|
- app/views/admin/applicant_course_name/_form.html.haml
|
343
348
|
- app/views/admin/applicant_endorsements/_applicant_endorsement.html.haml
|
344
349
|
- app/views/admin/applicant_references/_applicant_reference.html.haml
|
350
|
+
- app/views/admin/applicant_reviews/_applicant_review.html.haml
|
345
351
|
- app/views/admin/applicants/_form.html.haml
|
346
352
|
- app/views/admin/applicants/_form_applicant.html.haml
|
347
353
|
- app/views/admin/applicants/_form_approve.html.haml
|
@@ -395,6 +401,16 @@ files:
|
|
395
401
|
- app/views/effective/applicant_references/_form_declaration.html.haml
|
396
402
|
- app/views/effective/applicant_references/complete.html.haml
|
397
403
|
- app/views/effective/applicant_references/edit.html.haml
|
404
|
+
- app/views/effective/applicant_reviews/_applicant_review.html.haml
|
405
|
+
- app/views/effective/applicant_reviews/_content.html.haml
|
406
|
+
- app/views/effective/applicant_reviews/_dashboard.html.haml
|
407
|
+
- app/views/effective/applicant_reviews/_layout.html.haml
|
408
|
+
- app/views/effective/applicant_reviews/_recommendation.html.haml
|
409
|
+
- app/views/effective/applicant_reviews/_review.html.haml
|
410
|
+
- app/views/effective/applicant_reviews/recommendation.html.haml
|
411
|
+
- app/views/effective/applicant_reviews/review.html.haml
|
412
|
+
- app/views/effective/applicant_reviews/start.html.haml
|
413
|
+
- app/views/effective/applicant_reviews/submitted.html.haml
|
398
414
|
- app/views/effective/applicants/_applicant.html.haml
|
399
415
|
- app/views/effective/applicants/_content.html.haml
|
400
416
|
- app/views/effective/applicants/_course_amounts.html.haml
|
@@ -470,6 +486,7 @@ files:
|
|
470
486
|
- app/views/effective/memberships_mailer/applicant_endorsement_notification.liquid
|
471
487
|
- app/views/effective/memberships_mailer/applicant_missing_info.liquid
|
472
488
|
- app/views/effective/memberships_mailer/applicant_reference_notification.liquid
|
489
|
+
- app/views/effective/memberships_mailer/applicant_review_submitted.liquid
|
473
490
|
- app/views/effective/organizations/_dashboard.html.haml
|
474
491
|
- app/views/effective/organizations/_form.html.haml
|
475
492
|
- app/views/effective/organizations/_form_organization.html.haml
|