effective_cpd 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d431d1c016484d56c812b1e62e51203d8d6dcc9a626452e3e0275a194126f045
4
- data.tar.gz: af7ef23916669b65010a86afe274c65cc123662a95b30d69c96cd6767eae41f6
3
+ metadata.gz: 0b3c9aea2f12855203e8463c8e02648e5451327cef287302fee8d61de4dccba7
4
+ data.tar.gz: 10cc9891ca0f58b5a6e4bb065fac0906e4c51f160185b41a36b8c379cc62a62f
5
5
  SHA512:
6
- metadata.gz: 64768ebc20002cc568e939d0ed694edc7d293899a3470529a42a88100a3a94dfd27dbc379ed250cbf3a3439a4abef84b9cefa95f4d00edfba8fea9d9ecfbb9bc
7
- data.tar.gz: 91b7b3f4853dfd810c98039949f3ac1d00fc4d0a6ba95aa51745809d683b142ff21fc74ab397659b473d8620b3de1097be27e2b93065720ba09ec3f28a18aa67
6
+ metadata.gz: 16fb7e108faf4cce6b68c9664f8027e023a7e82c1e65a8adc54fbac0e15317a31e2d6f597c2dd54d2399cabf82ccbbae5bdd69da5ac2b7dc7629563083e6747f
7
+ data.tar.gz: 3ec497e4dedb5cecead7cf55e9f5615123820f206ecf8062edf032d3034493aa82e769d63cbe3cdf58e12c06f32dec756576640902fe71827131cc431ecaf73f
@@ -0,0 +1,19 @@
1
+ module Admin
2
+ class CpdBulkAuditsController < ApplicationController
3
+ before_action(:authenticate_user!) if defined?(Devise)
4
+ before_action { EffectiveResources.authorize!(self, :admin, :effective_cpd) }
5
+
6
+ include Effective::CrudController
7
+
8
+ resource_scope -> { EffectiveCpd.CpdBulkAudit.deep.all }
9
+ datatable -> { EffectiveResources.best('Admin::EffectiveCpdBulkAuditsDatatable').new }
10
+
11
+ private
12
+
13
+ def permitted_params
14
+ model = (params.key?(:effective_cpd_bulk_audit) ? :effective_cpd_bulk_audit : :cpd_bulk_audit)
15
+ params.require(model).permit!
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ module Admin
2
+ class EffectiveCpdBulkAuditAuditReviewersDatatable < Effective::Datatable
3
+
4
+ datatable do
5
+ order :updated_at, :desc
6
+
7
+ col :id, visible: false
8
+ col :updated_at, label: 'Updated', visible: false
9
+ col :created_at, label: 'Created', visible: false
10
+
11
+ col :first_name
12
+ col :last_name
13
+ col :email
14
+
15
+ actions_col(only: [:show, :edit])
16
+
17
+ end
18
+
19
+ collection do
20
+ current_user.class.send(EffectiveCpd.audit_reviewer_user_scope)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ module Admin
2
+ class EffectiveCpdBulkAuditAuditeesDatatable < Effective::Datatable
3
+
4
+ datatable do
5
+ order :updated_at, :desc
6
+
7
+ col :id, visible: false
8
+ col :updated_at, label: 'Updated', visible: false
9
+ col :created_at, label: 'Created', visible: false
10
+
11
+ col :first_name
12
+ col :last_name
13
+ col :email
14
+
15
+ actions_col(only: [:show, :edit])
16
+ end
17
+
18
+ collection do
19
+ current_user.class.send(EffectiveCpd.auditee_user_scope)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,25 @@
1
+ module Admin
2
+ class EffectiveCpdBulkAuditsDatatable < Effective::Datatable
3
+
4
+ datatable do
5
+ order :updated_at, :desc
6
+
7
+ col :id, visible: false
8
+ col :updated_at, label: 'Updated', visible: false
9
+ col :created_at, label: 'Created'
10
+
11
+ col :cpd_audit_level
12
+ col :audits
13
+ col :audit_reviewers_per_audit
14
+ col :notification_date
15
+ col :email_form_skip
16
+
17
+ actions_col
18
+ end
19
+
20
+ collection do
21
+ EffectiveCpd.CpdBulkAudit.all
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ module Effective
2
+ class CpdBulkAuditJob < ApplicationJob
3
+
4
+ def perform(id)
5
+ bulk_audit = EffectiveCpd.CpdBulkAudit.find(id)
6
+ bulk_audit.create_audits!
7
+ end
8
+
9
+ end
10
+ end
@@ -308,7 +308,7 @@ module EffectiveCpdAudit
308
308
  end
309
309
 
310
310
  def draft?
311
- !was_submitted?
311
+ !was_submitted? && !closed?
312
312
  end
313
313
 
314
314
  def in_progress?
@@ -72,6 +72,9 @@ module EffectiveCpdAuditLevel
72
72
  scope :deep, -> { all }
73
73
  scope :sorted, -> { order(:title) }
74
74
 
75
+ # For the Admin new cpd audit form
76
+ scope :new_cpd_audit_level_collection, -> { sorted }
77
+
75
78
  validates :title, presence: true
76
79
  validates :determinations, presence: true
77
80
  validates :recommendations, presence: true
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ # EffectiveCpdBulkAudit
4
+ #
5
+ # Mark your owner model with effective_cpd_bulk_audit to get all the includes
6
+
7
+ module EffectiveCpdBulkAudit
8
+ extend ActiveSupport::Concern
9
+
10
+ module Base
11
+ def effective_cpd_bulk_audit
12
+ include ::EffectiveCpdBulkAudit
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def effective_cpd_bulk_audit?; true; end
18
+ end
19
+
20
+ included do
21
+ attr_accessor :current_user
22
+
23
+ # App scoped
24
+ belongs_to :cpd_audit_level, polymorphic: true
25
+
26
+ log_changes if respond_to?(:log_changes)
27
+
28
+ effective_resource do
29
+ cpd_user_class_name :string
30
+
31
+ audits :integer
32
+ audit_reviewers_per_audit :integer
33
+
34
+ notification_date :date
35
+ email_form_skip :boolean
36
+
37
+ auditees_count :integer
38
+ audit_reviewers_count :integer
39
+
40
+ timestamps
41
+ end
42
+
43
+ scope :deep, -> { includes(:cpd_audit_level) }
44
+ scope :sorted, -> { order(:id) }
45
+
46
+ before_validation(if: -> { current_user.present? }) do
47
+ self.cpd_user_class_name ||= current_user.class.name
48
+ end
49
+
50
+ before_validation do
51
+ self.notification_date ||= Time.zone.now
52
+ end
53
+
54
+ before_validation(if: -> { cpd_user_scope.present? }) do
55
+ self.auditees_count ||= cpd_auditees.count()
56
+ self.audit_reviewers_count ||= cpd_audit_reviewers.count()
57
+ end
58
+
59
+ validates :cpd_user_class_name, presence: true
60
+
61
+ validates :audits, presence: true, numericality: { greater_than: 0, less_than_or_equal_to: 1000 }
62
+ validates :audit_reviewers_per_audit, presence: true, numericality: { greater_than: 0, less_than_or_equal_to: 3 }
63
+
64
+ validates :auditees_count, numericality: { greater_than: 0 }
65
+ validates :audit_reviewers_count, numericality: { greater_than: 0 }
66
+
67
+ validate(if: -> { cpd_user_scope.present? }) do
68
+ self.errors.add(:cpd_user_class_name, "expecting an effective_cpd_user") unless cpd_user_scope.respond_to?(:effective_cpd_user?)
69
+ end
70
+
71
+ validate(if: -> { audits.present? && auditees_count.present? }) do
72
+ self.errors.add(:audits, "can't be more than the number of auditees #{auditees_count}") if audits > auditees_count
73
+ end
74
+
75
+ validate(if: -> { audit_reviewers_per_audit.present? && audit_reviewers_count.present? }) do
76
+ self.errors.add(:audit_reviewers_per_audit, "can't be more than the number of audit reviewers #{audit_reviewers_count}") if audit_reviewers_per_audit > audit_reviewers_count
77
+ end
78
+
79
+ after_commit(on: :create) { create_bulk_audit_job! }
80
+ end
81
+
82
+ def to_s
83
+ 'bulk audit'
84
+ end
85
+
86
+ def cpd_user_scope
87
+ cpd_user_class_name.constantize.all if cpd_user_class_name.present?
88
+ end
89
+
90
+ def cpd_auditees
91
+ cpd_user_scope.send(EffectiveCpd.auditee_user_scope)
92
+ end
93
+
94
+ def cpd_audit_reviewers
95
+ cpd_user_scope.send(EffectiveCpd.audit_reviewer_user_scope)
96
+ end
97
+
98
+ def create_bulk_audit_job!
99
+ raise('must be persisted') unless persisted?
100
+
101
+ Effective::CpdBulkAuditJob.perform_later(id)
102
+ end
103
+
104
+ # Called by Effective::CpdBulkAuditJob
105
+ def create_audits!
106
+ save!
107
+
108
+ @auditees = cpd_auditees.order('RANDOM()').limit(audits)
109
+ @reviewers = cpd_audit_reviewers.order('RANDOM()').limit(audits).to_a
110
+
111
+ @auditees.each do |auditee|
112
+ reviewers = audit_reviewers_per_audit.times.map { next_audit_reviewer() }
113
+
114
+ cpd_audit = build_cpd_audit(auditee, reviewers)
115
+ cpd_audit.save!
116
+ end
117
+
118
+ true
119
+ end
120
+
121
+ def build_cpd_audit(auditee, reviewers)
122
+ raise('expected auditee cpd user') unless auditee.class.respond_to?(:effective_cpd_user?)
123
+
124
+ reviewers = Array(reviewers)
125
+ raise('expected audit reviewers') unless reviewers.all? { |reviewer| reviewer.try(:cpd_audit_reviewer?) }
126
+
127
+ cpd_audit = EffectiveCpd.CpdAudit.new(
128
+ cpd_audit_level: cpd_audit_level,
129
+ email_form_skip: email_form_skip?,
130
+ user: auditee,
131
+ notification_date: notification_date
132
+ )
133
+
134
+ reviewers.each do |reviewer|
135
+ cpd_audit.cpd_audit_reviews.build(
136
+ cpd_audit_level: cpd_audit_level,
137
+ email_form_skip: email_form_skip?,
138
+ user: reviewer
139
+ )
140
+ end
141
+
142
+ cpd_audit
143
+ end
144
+
145
+ # Round robin
146
+ def next_audit_reviewer
147
+ raise('expected @audit_reviewers to be set') unless @reviewers
148
+
149
+ @reviewers_index ||= -1
150
+
151
+ # Next Reviewer
152
+ @reviewers_index += 1
153
+ @reviewers_index = 0 if @reviewers_index >= @reviewers.length
154
+
155
+ @reviewers[@reviewers_index]
156
+ end
157
+
158
+ end
@@ -0,0 +1,5 @@
1
+ module Effective
2
+ class CpdBulkAudit < ActiveRecord::Base
3
+ effective_cpd_bulk_audit
4
+ end
5
+ end
@@ -3,7 +3,7 @@
3
3
  %h2 Audit
4
4
  = f.hidden_field :cpd_audit_level_type, value: EffectiveCpd.CpdAuditLevel.name
5
5
 
6
- = f.select :cpd_audit_level_id, EffectiveCpd.CpdAuditLevel.all.sorted, label: 'Audit level'
6
+ = f.select :cpd_audit_level_id, EffectiveCpd.CpdAuditLevel.new_cpd_audit_level_collection, label: 'Audit level'
7
7
 
8
8
  = f.date_field :notification_date, label: 'Date of notification', required: false,
9
9
  hint: "the starting date for any deadline calculations. leave blank for today's date"
@@ -0,0 +1 @@
1
+ = render('admin/cpd_bulk_audits/form_cpd_bulk_audit', cpd_bulk_audit: cpd_bulk_audit)
@@ -0,0 +1,60 @@
1
+ %h2 Bulk Create Audits
2
+
3
+ = effective_form_with(model: [:admin, cpd_bulk_audit], engine: true, url: effective_cpd.admin_cpd_bulk_audits_path) do |f|
4
+ = f.number_field :audits, label: 'How many audits to create', placeholder: 100
5
+ = f.number_field :audit_reviewers_per_audit, label: 'How many reviewers should be assigned to each audit', placeholder: 1
6
+
7
+ = f.hidden_field :cpd_audit_level_type, value: EffectiveCpd.CpdAuditLevel.name
8
+ = f.select :cpd_audit_level_id, EffectiveCpd.CpdAuditLevel.new_cpd_audit_level_collection, label: 'Audit level'
9
+
10
+ = f.date_field :notification_date, label: 'Date of notification', required: false, placeholder: Time.zone.now.strftime('%F'),
11
+ hint: "the starting date for any deadline calculations. leave blank for today's date"
12
+
13
+ %h3 Eligible Auditees
14
+ - datatable = EffectiveResources.best('Admin::EffectiveCpdBulkAuditAuditeesDatatable').new(self)
15
+ - raise('expected an auditees datatable') unless datatable.present?
16
+
17
+ %p The following #{pluralize(datatable.collection.count, 'auditee')} may be selected for audit:
18
+ = collapse('Show auditees...', card_class: '') do
19
+ = render_datatable(datatable)
20
+
21
+ %h3 Eligible Audit Reviewers
22
+ - datatable = EffectiveResources.best('Admin::EffectiveCpdBulkAuditAuditReviewersDatatable').new(self)
23
+ - raise('expected an auditees datatable') unless datatable.present?
24
+
25
+ %p The following #{pluralize(datatable.collection.count, 'audit reviewer')} may be selected to review audits:
26
+ = collapse('Show audit reviewers...', card_class: '') do
27
+ = render_datatable(datatable)
28
+
29
+ %h3 Email to send
30
+ = f.check_box :email_form_skip, label: 'Do not send email'
31
+
32
+ = f.show_if :email_form_skip, true do
33
+ %p No emails will be sent.
34
+
35
+ = f.hide_if :email_form_skip, true do
36
+ %p
37
+ The
38
+ - email = Effective::EmailTemplate.where(template_name: :cpd_audit_opened).first!
39
+ = link_to('cpd_audit_opened email', effective_email_templates.edit_admin_email_template_path(email), target: '_blank')
40
+ email will be sent to each auditee.
41
+
42
+ %p
43
+ The
44
+ - email = Effective::EmailTemplate.where(template_name: :cpd_audit_review_opened).first!
45
+ = link_to('cpd_audit_review_opened email', effective_email_templates.edit_admin_email_template_path(email), target: '_blank')
46
+ email will be sent to each audit reviewer.
47
+
48
+ %h3 Create Audits
49
+
50
+ %p
51
+ Upon clicking the button below, the audits will be created in a background process.
52
+
53
+ %p
54
+ The auditees will be randomly selected, and the audit reviewers assigned in a round robin fashion.
55
+ This process will take a few minutes.
56
+
57
+ %p
58
+ All created audits will be displayed on the #{link_to 'Audits', effective_cpd.admin_cpd_audits_path} screen.
59
+
60
+ = f.submit 'Create Bulk Audits', center: true, 'data-confirm': "Really create audits?"
@@ -1,5 +1,18 @@
1
1
  %h2 Continuing Professional Development
2
2
 
3
+ - # In progress
4
+ - cpd_audit = current_user.cpd_audits.in_progress.first
5
+
6
+ - if cpd_audit.present? && cpd_audit.in_progress?
7
+ %p Your audit is in progress.
8
+
9
+ %p
10
+ Please
11
+ = link_to("Continue audit", effective_cpd.cpd_audit_build_path(cpd_audit, cpd_audit.next_step), 'data-turbolinks' => false, class: 'btn btn-primary')
12
+ to continue.
13
+
14
+ %hr
15
+
3
16
  - # Auditee datatables (4)
4
17
  - auditing = EffectiveCpdAvailableAuditsDatatable.new(self)
5
18
  - if auditing.present?
@@ -22,6 +22,8 @@ EffectiveCpd.setup do |config|
22
22
  config.cpd_audit_reviews_table_name = :cpd_audit_reviews
23
23
  config.cpd_audit_review_items_table_name = :cpd_audit_review_items
24
24
 
25
+ config.cpd_bulk_audits_table_name = :cpd_bulk_audits
26
+
25
27
  # Layout Settings
26
28
  # Configure the Layout per controller, or all at once
27
29
  config.layout = {
@@ -35,6 +37,7 @@ EffectiveCpd.setup do |config|
35
37
  # config.cpd_audit_class_name = 'Effective::CpdAudit'
36
38
  # config.cpd_audit_level_class_name = 'Effective::CpdAuditLevel'
37
39
  # config.cpd_audit_review_class_name = 'Effective::CpdAuditReview'
40
+ # config.cpd_bulk_audit_class_name = 'Effective::CpdBulkAudit'
38
41
 
39
42
  # Program label settings
40
43
  config.program_label = 'CPD' # CPD or MCE
data/config/routes.rb CHANGED
@@ -46,6 +46,8 @@ EffectiveCpd::Engine.routes.draw do
46
46
 
47
47
  resources :cpd_audits, except: [:show]
48
48
  resources :cpd_audit_reviews
49
+
50
+ resources :cpd_bulk_audits, only: [:index, :new, :create]
49
51
  end
50
52
 
51
53
  end
@@ -305,5 +305,22 @@ class CreateEffectiveCpd < ActiveRecord::Migration[6.0]
305
305
  t.datetime :created_at
306
306
  end
307
307
 
308
+ create_table <%= @cpd_bulk_audits_table_name %> do |t|
309
+ t.integer :cpd_audit_level_id
310
+ t.string :cpd_audit_level_type
311
+
312
+ t.integer :audits
313
+ t.integer :audit_reviewers_per_audit
314
+
315
+ t.date :notification_date
316
+ t.boolean :email_form_skip
317
+
318
+ t.string :user_klass
319
+ t.integer :auditees_count
320
+ t.integer :audit_reviewers_count
321
+
322
+ t.timestamps
323
+ end
324
+
308
325
  end
309
326
  end
@@ -11,11 +11,11 @@ module EffectiveCpd
11
11
  initializer 'effective_cpd.active_record' do |app|
12
12
  ActiveSupport.on_load :active_record do
13
13
  ActiveRecord::Base.extend(EffectiveCpdUser::Base)
14
- #ActiveRecord::Base.extend(EffectiveCpdCycle::Base)
15
14
  ActiveRecord::Base.extend(EffectiveCpdStatement::Base)
16
15
  ActiveRecord::Base.extend(EffectiveCpdAudit::Base)
17
16
  ActiveRecord::Base.extend(EffectiveCpdAuditLevel::Base)
18
17
  ActiveRecord::Base.extend(EffectiveCpdAuditReview::Base)
18
+ ActiveRecord::Base.extend(EffectiveCpdBulkAudit::Base)
19
19
  end
20
20
  end
21
21
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveCpd
2
- VERSION = '1.1.2'
2
+ VERSION = '1.2.0'
3
3
  end
data/lib/effective_cpd.rb CHANGED
@@ -13,11 +13,11 @@ module EffectiveCpd
13
13
  :cpd_audit_levels_table_name, :cpd_audit_level_sections_table_name,
14
14
  :cpd_audit_level_questions_table_name, :cpd_audit_level_question_options_table_name,
15
15
  :cpd_audits_table_name, :cpd_audit_responses_table_name, :cpd_audit_response_options_table_name,
16
- :cpd_audit_reviews_table_name, :cpd_audit_review_items_table_name,
16
+ :cpd_audit_reviews_table_name, :cpd_audit_review_items_table_name, :cpd_bulk_audits_table_name,
17
17
  :program_label, :cycle_label, :credit_label, :layout, :auditee_user_scope, :audit_reviewer_user_scope,
18
18
  :use_effective_messaging,
19
19
  :mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_admin, :mailer_subject, :use_effective_email_templates,
20
- :cpd_statement_class_name, :cpd_audit_class_name, :cpd_audit_level_class_name, :cpd_audit_review_class_name
20
+ :cpd_statement_class_name, :cpd_audit_class_name, :cpd_audit_level_class_name, :cpd_audit_review_class_name, :cpd_bulk_audit_class_name
21
21
  ]
22
22
  end
23
23
 
@@ -43,6 +43,10 @@ module EffectiveCpd
43
43
  cpd_audit_review_class_name&.constantize || Effective::CpdAuditReview
44
44
  end
45
45
 
46
+ def self.CpdBulkAudit
47
+ cpd_bulk_audit_class_name&.constantize || Effective::CpdBulkAudit
48
+ end
49
+
46
50
  def self.use_effective_messaging?
47
51
  defined?(EffectiveMessaging) && !!use_effective_messaging
48
52
  end
@@ -43,6 +43,8 @@ module EffectiveCpd
43
43
  @cpd_audit_reviews_table_name = ':' + EffectiveCpd.cpd_audit_reviews_table_name.to_s
44
44
  @cpd_audit_review_items_table_name = ':' + EffectiveCpd.cpd_audit_review_items_table_name.to_s
45
45
 
46
+ @cpd_bulk_audits_table_name = ':' + EffectiveCpd.cpd_bulk_audits_table_name.to_s
47
+
46
48
  migration_template ('../' * 3) + 'db/migrate/01_create_effective_cpd.rb.erb', 'db/migrate/create_effective_cpd.rb'
47
49
  end
48
50
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_cpd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.2.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: 2023-01-20 00:00:00.000000000 Z
11
+ date: 2023-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -150,6 +150,20 @@ dependencies:
150
150
  - - ">="
151
151
  - !ruby/object:Gem::Version
152
152
  version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: effective_developer
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: effective_email_templates
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -178,6 +192,20 @@ dependencies:
178
192
  - - ">="
179
193
  - !ruby/object:Gem::Version
180
194
  version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: effective_roles
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
181
209
  description: Continuing professional development and audits rails engine
182
210
  email:
183
211
  - info@codeandeffect.com
@@ -199,6 +227,7 @@ files:
199
227
  - app/controllers/admin/cpd_audit_levels_controller.rb
200
228
  - app/controllers/admin/cpd_audit_reviews_controller.rb
201
229
  - app/controllers/admin/cpd_audits_controller.rb
230
+ - app/controllers/admin/cpd_bulk_audits_controller.rb
202
231
  - app/controllers/admin/cpd_categories_controller.rb
203
232
  - app/controllers/admin/cpd_cycles_controller.rb
204
233
  - app/controllers/admin/cpd_rules_controller.rb
@@ -215,6 +244,9 @@ files:
215
244
  - app/datatables/admin/effective_cpd_audit_levels_datatable.rb
216
245
  - app/datatables/admin/effective_cpd_audit_reviews_datatable.rb
217
246
  - app/datatables/admin/effective_cpd_audits_datatable.rb
247
+ - app/datatables/admin/effective_cpd_bulk_audit_audit_reviewers_datatable.rb
248
+ - app/datatables/admin/effective_cpd_bulk_audit_auditees_datatable.rb
249
+ - app/datatables/admin/effective_cpd_bulk_audits_datatable.rb
218
250
  - app/datatables/admin/effective_cpd_categories_datatable.rb
219
251
  - app/datatables/admin/effective_cpd_cycles_datatable.rb
220
252
  - app/datatables/admin/effective_cpd_rules_datatable.rb
@@ -229,10 +261,12 @@ files:
229
261
  - app/datatables/effective_cpd_completed_statements_datatable.rb
230
262
  - app/helpers/effective_cpd_audits_helper.rb
231
263
  - app/helpers/effective_cpd_helper.rb
264
+ - app/jobs/effective/cpd_bulk_audit_job.rb
232
265
  - app/mailers/effective/cpd_mailer.rb
233
266
  - app/models/concerns/effective_cpd_audit.rb
234
267
  - app/models/concerns/effective_cpd_audit_level.rb
235
268
  - app/models/concerns/effective_cpd_audit_review.rb
269
+ - app/models/concerns/effective_cpd_bulk_audit.rb
236
270
  - app/models/concerns/effective_cpd_statement.rb
237
271
  - app/models/concerns/effective_cpd_user.rb
238
272
  - app/models/effective/cpd_activity.rb
@@ -245,6 +279,7 @@ files:
245
279
  - app/models/effective/cpd_audit_response_option.rb
246
280
  - app/models/effective/cpd_audit_review.rb
247
281
  - app/models/effective/cpd_audit_review_item.rb
282
+ - app/models/effective/cpd_bulk_audit.rb
248
283
  - app/models/effective/cpd_category.rb
249
284
  - app/models/effective/cpd_cycle.rb
250
285
  - app/models/effective/cpd_rule.rb
@@ -278,6 +313,8 @@ files:
278
313
  - app/views/admin/cpd_audits/_form_new.html.haml
279
314
  - app/views/admin/cpd_audits/_form_process.html.haml
280
315
  - app/views/admin/cpd_audits/_status.html.haml
316
+ - app/views/admin/cpd_bulk_audits/_form.html.haml
317
+ - app/views/admin/cpd_bulk_audits/_form_cpd_bulk_audit.html.haml
281
318
  - app/views/admin/cpd_categories/_form.html.haml
282
319
  - app/views/admin/cpd_categories/_form_cpd_category.html.haml
283
320
  - app/views/admin/cpd_cycles/_form.html.haml