effective_memberships 0.6.13 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/admin/applicant_reviews_controller.rb +19 -0
  3. data/app/controllers/effective/applicant_reviews_controller.rb +13 -0
  4. data/app/datatables/admin/effective_applicant_reviews_datatable.rb +24 -0
  5. data/app/datatables/effective_applicant_reviews_datatable.rb +25 -0
  6. data/app/datatables/effective_available_applicant_reviews_datatable.rb +40 -0
  7. data/app/mailers/effective/memberships_mailer.rb +43 -0
  8. data/app/models/concerns/effective_memberships_applicant.rb +23 -2
  9. data/app/models/concerns/effective_memberships_applicant_review.rb +34 -68
  10. data/app/models/concerns/effective_memberships_user.rb +6 -0
  11. data/app/views/admin/applicant_reviews/_applicant_review.html.haml +1 -0
  12. data/app/views/admin/applicants/_form_applicant.html.haml +4 -0
  13. data/app/views/admin/applicants/_status.html.haml +2 -2
  14. data/app/views/effective/applicant_reviews/_applicant_review.html.haml +4 -0
  15. data/app/views/effective/applicant_reviews/_content.html.haml +8 -0
  16. data/app/views/effective/applicant_reviews/_dashboard.html.haml +36 -0
  17. data/app/views/effective/applicant_reviews/_layout.html.haml +3 -0
  18. data/app/views/effective/applicant_reviews/_recommendation.html.haml +23 -0
  19. data/app/views/effective/applicant_reviews/_review.html.haml +1 -0
  20. data/app/views/effective/applicant_reviews/recommendation.html.haml +20 -0
  21. data/app/views/effective/applicant_reviews/review.html.haml +14 -0
  22. data/app/views/effective/applicant_reviews/start.html.haml +18 -0
  23. data/app/views/effective/applicant_reviews/submitted.html.haml +15 -0
  24. data/app/views/effective/applicants/_summary.html.haml +4 -3
  25. data/app/views/effective/memberships_mailer/applicant_review_submitted.liquid +19 -0
  26. data/config/routes.rb +6 -0
  27. data/lib/effective_memberships/version.rb +1 -1
  28. metadata +19 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58da6947ec96b076bd125a190e31ade30e7964b6dc796423dc7387efa156a246
4
- data.tar.gz: 5805aa420a911f2abbb4d38ceaf1d6d743a3932e3b47a14b3b1e4a8796afd0bd
3
+ metadata.gz: 3972d4221b4931ed7f157f87ef8a7d9c9a1ad785679599a13c3d38e37fd48e56
4
+ data.tar.gz: 4a19e5c29db9c7ee41fd67177cda71197adb743f1f4eaaf97116192af82c562b
5
5
  SHA512:
6
- metadata.gz: ea84383f2dbd0763c31e4c8a1c13f16d474d96e749502717dec4825cdbd50eee9fe3dbf3572650dcccedc3f05785bc283c0451fd9ac51fee5f17fd7fa738e7b6
7
- data.tar.gz: f0d0dad74b75782b25fc76f786b6e1d042faa591941ebc747ac85d24301dda54e8d3fc5be080ef5827ac251de0f60d23eafea443106565fb872fd2ccdb9bf1a6
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(&:completed?) >= min_applicant_reviews)
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 category model with effective_memberships_applicant_review to get all the includes
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
- ['Accept', 'Reject']
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, # Just Started
37
- :conflicted, # Conflict of Interest
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
- conflict: 'Conflict of Interest',
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: :owner) }
62
+ scope :deep, -> { includes(:reviewer, applicant: :user) }
89
63
 
90
- with_options(if: -> { current_step == :conflict }) do
91
- validates :conflict_of_interest, inclusion: { in: [true, false] }
92
- validates :comments, presence: true, if: -> { conflict_of_interest? }
93
- end
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
- validates :recommendation, absence: true, if: -> { done? && conflict_of_interest? }
69
+ with_options(if: -> { submitted? }) do
70
+ validates :recommendation, presence: true
96
71
 
97
- after_commit(on: :create, if: -> { applicant.completed? }) { notify! }
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
- 'applicant review'
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
- !draft?
86
+ submitted?
109
87
  end
110
88
 
111
- def conflict_of_interest!
112
- update!(conflict_of_interest: true, recommendation: nil)
113
- conflicted!
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
- def accept!
122
- assign_attributes(recommendation: 'Accept')
123
- accepted!
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 reject!
132
- assign_attributes(recommendation: 'Reject')
133
- rejected!
134
-
135
- applicant.save!
99
+ def submit!
100
+ submitted!
101
+ applicant.try_reviewed!
136
102
 
137
- after_commit { send_email(:applicant_review_completed) }
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, email_form_params) unless email_form_skip?
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(&:completed?)
110
+ = applicant.applicant_reviews.count(&:submitted?)
111
111
  = '/'
112
112
  = applicant.min_applicant_reviews
113
- Reviews Completed
113
+ Reviews Submitted
114
114
  - else
115
115
  %p
116
116
  = icon('check', class: 'small-1')
@@ -0,0 +1,4 @@
1
+ .effective-applicant-review
2
+ - applicant_review.render_steps.each do |partial|
3
+ - applicant_review.render_step = partial
4
+ = render "effective/applicant_reviews/#{partial}", applicant_review: applicant_review
@@ -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,3 @@
1
+ .row
2
+ .col-lg-3.mb-3= render_wizard_sidebar(resource)
3
+ .col-lg-9= yield
@@ -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
- - if applicant.orders.present?
57
+ - orders = applicant.orders.select { |order| EffectiveResources.authorized?(self, :show, order) }
58
+ - if orders.present?
58
59
  %tr
59
- %th Order#{'s' if applicant.orders.length > 1}
60
+ %th Order#{'s' if orders.length > 1}
60
61
  %td
61
- - applicant.orders.each do |order|
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
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveMemberships
2
- VERSION = '0.6.13'
2
+ VERSION = '0.7.0'
3
3
  end
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.6.13
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-14 00:00:00.000000000 Z
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