effective_cpd 0.6.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,87 +1,5 @@
1
1
  module Effective
2
2
  class CpdAuditLevel < ActiveRecord::Base
3
- has_many_rich_texts
4
-
5
- # For each cpd audit and cpd audit review wizard step
6
- # rich_text_all_steps_audit_content
7
- # rich_text_step_audit_content
8
-
9
- # rich_text_all_steps_audit_review_content
10
- # rich_text_step_audit_review_content
11
-
12
- has_many :cpd_audit_level_sections, -> { CpdAuditLevelSection.sorted }, inverse_of: :cpd_audit_level, dependent: :destroy
13
- accepts_nested_attributes_for :cpd_audit_level_sections, allow_destroy: true
14
-
15
- has_many :cpd_audit_level_questions, -> { CpdAuditLevelQuestion.sorted }, through: :cpd_audit_level_sections
16
-
17
- has_many :cpd_audit_reviews, -> { CpdAuditReview.sorted }, inverse_of: :cpd_audit_level, dependent: :destroy
18
- accepts_nested_attributes_for :cpd_audit_reviews, allow_destroy: true
19
-
20
- has_many :cpd_audits
21
-
22
- if respond_to?(:log_changes)
23
- log_changes(except: [:cpd_audits, :cpd_audit_reviews, :cpd_audit_level_sections, :cpd_audit_level_questions])
24
- end
25
-
26
- effective_resource do
27
- title :string
28
-
29
- determinations :text # Final determination by auditor
30
- recommendations :text # Recommendations by audit reviewers
31
-
32
- days_to_submit :integer # For auditee to submit statement
33
- days_to_review :integer # For auditor/audit_review to be completed
34
-
35
- conflict_of_interest :boolean # Feature flags
36
- can_request_exemption :boolean
37
- can_request_extension :boolean
38
-
39
- days_to_declare_conflict :integer
40
- days_to_request_exemption :integer
41
- days_to_request_extension :integer
42
-
43
- timestamps
44
- end
45
-
46
- serialize :determinations, Array
47
- serialize :recommendations, Array
48
-
49
- scope :deep, -> { all }
50
- scope :sorted, -> { order(:title) }
51
-
52
- validates :title, presence: true
53
- validates :determinations, presence: true
54
- validates :recommendations, presence: true
55
-
56
- validates :days_to_submit, numericality: { greater_than: 0, allow_nil: true }
57
- validates :days_to_review, numericality: { greater_than: 0, allow_nil: true }
58
-
59
- validates :days_to_declare_conflict, presence: true, if: -> { conflict_of_interest? }
60
- validates :days_to_declare_conflict, numericality: { greater_than: 0, allow_nil: true }
61
-
62
- validates :days_to_request_exemption, presence: true, if: -> { can_request_exemption? }
63
- validates :days_to_request_exemption, numericality: { greater_than: 0, allow_nil: true }
64
-
65
- validates :days_to_request_extension, presence: true, if: -> { can_request_extension? }
66
- validates :days_to_request_extension, numericality: { greater_than: 0, allow_nil: true }
67
-
68
- before_destroy do
69
- if (count = cpd_audits.length) > 0
70
- raise("#{count} audits belong to this audit level")
71
- end
72
- end
73
-
74
- def to_s
75
- title.presence || 'audit level'
76
- end
77
-
78
- def determinations
79
- Array(self[:determinations]) - [nil, '']
80
- end
81
-
82
- def recommendations
83
- Array(self[:recommendations]) - [nil, '']
84
- end
85
-
3
+ effective_cpd_audit_level
86
4
  end
87
5
  end
@@ -25,6 +25,7 @@ module Effective
25
25
  end
26
26
 
27
27
  scope :submitted, -> { where(cpd_audit: Effective::CpdAudit.where.not(submitted_at: nil)) }
28
+ scope :sorted, -> { order(:id) }
28
29
  scope :deep, -> { includes(:cpd_audit, :cpd_audit_level_question) }
29
30
 
30
31
  before_validation(if: -> { cpd_audit_level_question.present? }) do
@@ -1,228 +1,5 @@
1
1
  module Effective
2
2
  class CpdAuditReview < ActiveRecord::Base
3
- attr_accessor :current_user
4
- attr_accessor :current_step
5
-
6
- belongs_to :cpd_audit
7
- belongs_to :cpd_audit_level
8
- belongs_to :user, polymorphic: true # Auditor
9
-
10
- has_many :cpd_audit_review_items, -> { CpdAuditReviewItem.sorted }, inverse_of: :cpd_audit_review, dependent: :destroy
11
- accepts_nested_attributes_for :cpd_audit_review_items, reject_if: :all_blank, allow_destroy: true
12
-
13
- if respond_to?(:log_changes)
14
- log_changes(to: :cpd_audit, except: :wizard_steps)
15
- end
16
-
17
- acts_as_email_form
18
- acts_as_tokened
19
- acts_as_reportable if respond_to?(:acts_as_reportable)
20
-
21
- acts_as_wizard(
22
- start: 'Start',
23
- information: 'Information',
24
- instructions: 'Instructions',
25
-
26
- # Optional based on cpd_audit_level options
27
- conflict: 'Conflict of Interest',
28
-
29
- waiting: 'Waiting on Auditee Submission',
30
-
31
- statements: 'Review CPD Statements',
32
- # ... There will be one step per cpd_statement here. "statement1"
33
-
34
- questionnaire: 'Review Questionnaire Responses',
35
- # ... There will be one step per cpd_audit_level_sections here
36
-
37
- recommendation: 'Recommendation',
38
- submit: 'Confirm & Submit',
39
- complete: 'Complete'
40
- )
41
-
42
- effective_resource do
43
- token :string
44
- due_date :date
45
-
46
- # Auditor response
47
- conflict_of_interest :boolean
48
- conflict_of_interest_reason :text
49
-
50
- # Rolling comments
51
- comments :text
52
-
53
- # Recommendation Step
54
- recommendation :string
55
-
56
- # Status Dates
57
- submitted_at :datetime
58
-
59
- # acts_as_statused
60
- # I'm not using acts_as_statused yet, but I probably will later
61
- status :string
62
- status_steps :text
63
-
64
- # Wizard Progress
65
- wizard_steps :text
66
-
67
- timestamps
68
- end
69
-
70
- scope :deep, -> { includes(:cpd_audit, :cpd_audit_level, :user) }
71
- scope :sorted, -> { order(:id) }
72
-
73
- scope :available, -> { where(submitted_at: nil) }
74
- scope :completed, -> { where.not(submitted_at: nil) }
75
-
76
- # effective_reports
77
- def reportable_scopes
78
- { available: nil, completed: nil }
79
- end
80
-
81
- before_validation(if: -> { new_record? }) do
82
- self.cpd_audit_level ||= cpd_audit&.cpd_audit_level
83
- self.due_date ||= deadline_to_review()
84
- end
85
-
86
- validate(if: -> { recommendation.present? }) do
87
- unless cpd_audit_level.recommendations.include?(recommendation)
88
- self.errors.add(:recommendation, 'must exist in this audit level')
89
- end
90
- end
91
-
92
- after_commit(on: :create) { send_email(:cpd_audit_review_opened) }
93
- after_commit(on: :destroy) { cpd_audit.review! }
94
-
95
- def to_s
96
- 'audit review'
97
- end
98
-
99
- def to_s
100
- persisted? ? "#{cpd_audit_level} Audit Review by #{user}" : 'audit review'
101
- end
102
-
103
- # Find or build
104
- def cpd_audit_review_item(item)
105
- unless item.kind_of?(CpdAuditResponse) || item.kind_of?(CpdStatementActivity)
106
- raise("expected a cpd_audit_response or cpd_statement_activity")
107
- end
108
-
109
- cpd_audit_review_item = cpd_audit_review_items.find { |cari| cari.item == item }
110
- cpd_audit_review_item ||= cpd_audit_review_items.build(item: item)
111
- end
112
-
113
- # The dynamic CPD Statement review steps
114
- def auditee_cpd_statements
115
- cpd_audit.user.cpd_statements.select do |cpd_statement|
116
- cpd_statement.completed? && (submitted_at.blank? || cpd_statement.submitted_at < submitted_at)
117
- end
118
- end
119
-
120
- def cpd_statement(wizard_step)
121
- cpd_cycle_id = (wizard_step.to_s.split('statement').last.to_i rescue false)
122
- auditee_cpd_statements.find { |cpd_statement| cpd_statement.cpd_cycle_id == cpd_cycle_id }
123
- end
124
-
125
- def dynamic_wizard_statement_steps
126
- @statement_steps ||= auditee_cpd_statements.each_with_object({}) do |cpd_statement, h|
127
- h["statement#{cpd_statement.cpd_cycle_id}".to_sym] = "#{cpd_statement.cpd_cycle.to_s} Activities"
128
- end
129
- end
130
-
131
- # The dynamic CPD Audit Level Sections steps
132
- def cpd_audit_level_section(wizard_step)
133
- position = (wizard_step.to_s.split('section').last.to_i rescue false)
134
- cpd_audit_level.cpd_audit_level_sections.find { |section| (section.position + 1) == position }
135
- end
136
-
137
- def dynamic_wizard_questionnaire_steps
138
- @questionnaire_steps ||= cpd_audit_level.cpd_audit_level_sections.each_with_object({}) do |section, h|
139
- h["section#{section.position+1}".to_sym] = section.title
140
- end
141
- end
142
-
143
- def dynamic_wizard_steps
144
- dynamic_wizard_statement_steps.merge(dynamic_wizard_questionnaire_steps)
145
- end
146
-
147
- def can_visit_step?(step)
148
- return (step == :complete) if completed? # Can only view complete step once submitted
149
- can_revisit_completed_steps(step)
150
- end
151
-
152
- def required_steps
153
- steps = [:start, :information, :instructions]
154
-
155
- steps << :conflict if cpd_audit_level.conflict_of_interest?
156
-
157
- if conflict_of_interest?
158
- return steps + [:submit, :complete]
159
- end
160
-
161
- steps += [:waiting] unless ready?
162
-
163
- steps += [:statements] + dynamic_wizard_statement_steps.keys
164
- steps += [:questionnaire] + dynamic_wizard_questionnaire_steps.keys
165
- steps += [:recommendation, :submit, :complete]
166
-
167
- steps
168
- end
169
-
170
- def wizard_step_title(step)
171
- WIZARD_STEPS[step] || dynamic_wizard_steps.fetch(step)
172
- end
173
-
174
- # Called by CpdAudit.extension_granted
175
- def extension_granted!
176
- self.due_date = deadline_to_review()
177
- end
178
-
179
- # Called by CpdAudit.submit!
180
- def ready!
181
- send_email(:cpd_audit_review_ready)
182
- end
183
-
184
- # Called by review wizard submit step
185
- def submit!
186
- update!(submitted_at: Time.zone.now)
187
- cpd_audit.review! # maybe go from submitted->removed
188
-
189
- send_email(:cpd_audit_review_submitted)
190
- end
191
-
192
- # When ready, the applicant review wizard hides the waiting step
193
- def ready?
194
- cpd_audit&.was_submitted?
195
- end
196
-
197
- def in_progress?
198
- submitted_at.blank?
199
- end
200
-
201
- def completed?
202
- submitted_at.present?
203
- end
204
-
205
- def email_form_defaults(action)
206
- { from: EffectiveCpd.mailer_sender }
207
- end
208
-
209
- def send_email(email)
210
- EffectiveCpd.send_email(email, self, email_form_params) unless email_form_skip?
211
- true
212
- end
213
-
214
- def deadline_to_conflict_of_interest
215
- cpd_audit.deadline_to_conflict_of_interest
216
- end
217
-
218
- def deadline_to_review
219
- return nil unless cpd_audit_level&.days_to_review.present?
220
-
221
- date = cpd_audit.deadline_to_submit
222
- return nil unless date.present?
223
-
224
- EffectiveResources.advance_date(date, business_days: cpd_audit_level.days_to_review)
225
- end
226
-
3
+ effective_cpd_audit_review
227
4
  end
228
5
  end
@@ -5,7 +5,7 @@
5
5
  = f.date_field :start_at,
6
6
  hint: "The first date statements may be submited for this #{cpd_cycle_label}"
7
7
 
8
- = f.date_field :end_at,
8
+ = f.date_field :end_at, date_linked: false,
9
9
  hint: "The last date statements may be created for this #{cpd_cycle_label}. leave blank for no end date."
10
10
 
11
11
  = f.number_field :required_score,
@@ -0,0 +1,15 @@
1
+ %h2 Statements
2
+ - datatable = Admin::EffectiveCpdStatementsDatatable.new(user: user)
3
+ = render_datatable(datatable, inline: true)
4
+
5
+ %hr
6
+
7
+ %h2 Activities
8
+ - datatable = Admin::EffectiveCpdStatementActivitiesDatatable.new(user: user)
9
+ = render_datatable(datatable, inline: true)
10
+
11
+ %hr
12
+
13
+ %h2 Audits
14
+ - datatable = Admin::EffectiveCpdAuditsDatatable.new(user: user)
15
+ = render_datatable(datatable)
@@ -18,6 +18,8 @@
18
18
  .mt-4
19
19
  %p Please submit a CPD statement for the following available #{cpd_cycles_label}:
20
20
  = render_datatable(available, simple: true)
21
+ - else
22
+ %p There are no #{cpd_cycles_label} available to submit. When there are, we'll show them here.
21
23
 
22
24
  - completed = EffectiveCpdCompletedStatementsDatatable.new(self)
23
25
  - if completed.present?
@@ -32,6 +32,9 @@ EffectiveCpd.setup do |config|
32
32
  # CPD Class Settings
33
33
  # Configure the class responsible for the cpd statements.
34
34
  # config.cpd_statement_class_name = 'Effective::CpdStatement'
35
+ # config.cpd_audit_class_name = 'Effective::CpdAudit'
36
+ # config.cpd_audit_level_class_name = 'Effective::CpdAuditLevel'
37
+ # config.cpd_audit_review_class_name = 'Effective::CpdAuditReview'
35
38
 
36
39
  # Program label settings
37
40
  config.program_label = 'CPD' # CPD or MCE
@@ -120,6 +120,8 @@ class CreateEffectiveCpd < ActiveRecord::Migration[6.0]
120
120
 
121
121
  create_table <%= @cpd_audit_levels_table_name %> do |t|
122
122
  t.string :title
123
+ t.boolean :anonymous, default: false
124
+
123
125
  t.text :determinations
124
126
  t.text :recommendations
125
127
 
@@ -172,13 +174,19 @@ class CreateEffectiveCpd < ActiveRecord::Migration[6.0]
172
174
  end
173
175
 
174
176
  create_table <%= @cpd_audits_table_name %> do |t|
175
- t.references :cpd_audit_level
177
+ t.intger :cpd_audit_level_id
178
+ t.string :cpd_audit_level_type
176
179
 
177
180
  t.integer :user_id
178
181
  t.string :user_type
179
182
 
180
183
  t.date :due_date
181
184
 
185
+ t.string :anonymous_name
186
+ t.string :selection
187
+ t.string :region
188
+ t.text :notes
189
+
182
190
  t.date :notification_date
183
191
  t.date :extension_date
184
192
 
@@ -213,8 +221,11 @@ class CreateEffectiveCpd < ActiveRecord::Migration[6.0]
213
221
  end
214
222
 
215
223
  create_table <%= @cpd_audit_reviews_table_name %> do |t|
216
- t.references :cpd_audit_level
217
- t.references :cpd_audit
224
+ t.integer :cpd_audit_level_id
225
+ t.string :cpd_audit_level_type
226
+
227
+ t.integer :cpd_audit_id
228
+ t.string :cpd_audit_type
218
229
 
219
230
  t.integer :user_id
220
231
  t.string :user_type
@@ -11,7 +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)
14
15
  ActiveRecord::Base.extend(EffectiveCpdStatement::Base)
16
+ ActiveRecord::Base.extend(EffectiveCpdAudit::Base)
17
+ ActiveRecord::Base.extend(EffectiveCpdAuditLevel::Base)
18
+ ActiveRecord::Base.extend(EffectiveCpdAuditReview::Base)
15
19
  end
16
20
  end
17
21
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveCpd
2
- VERSION = '0.6.7'
2
+ VERSION = '1.0.0'
3
3
  end
data/lib/effective_cpd.rb CHANGED
@@ -16,7 +16,7 @@ module EffectiveCpd
16
16
  :cpd_audit_reviews_table_name, :cpd_audit_review_items_table_name,
17
17
  :program_label, :cycle_label, :credit_label, :layout, :auditee_user_scope, :audit_reviewer_user_scope,
18
18
  :mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_admin, :mailer_subject, :use_effective_email_templates,
19
- :cpd_statement_class_name
19
+ :cpd_statement_class_name, :cpd_audit_class_name, :cpd_audit_level_class_name, :cpd_audit_review_class_name
20
20
  ]
21
21
  end
22
22
 
@@ -30,4 +30,16 @@ module EffectiveCpd
30
30
  cpd_statement_class_name&.constantize || Effective::CpdStatement
31
31
  end
32
32
 
33
+ def self.CpdAudit
34
+ cpd_audit_class_name&.constantize || Effective::CpdAudit
35
+ end
36
+
37
+ def self.CpdAuditLevel
38
+ cpd_audit_level_class_name&.constantize || Effective::CpdAuditLevel
39
+ end
40
+
41
+ def self.CpdAuditReview
42
+ cpd_audit_review_class_name&.constantize || Effective::CpdAuditReview
43
+ end
44
+
33
45
  end
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: 0.6.7
4
+ version: 1.0.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-05 00:00:00.000000000 Z
11
+ date: 2023-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -216,6 +216,9 @@ files:
216
216
  - app/helpers/effective_cpd_audits_helper.rb
217
217
  - app/helpers/effective_cpd_helper.rb
218
218
  - app/mailers/effective/cpd_mailer.rb
219
+ - app/models/concerns/effective_cpd_audit.rb
220
+ - app/models/concerns/effective_cpd_audit_level.rb
221
+ - app/models/concerns/effective_cpd_audit_review.rb
219
222
  - app/models/concerns/effective_cpd_statement.rb
220
223
  - app/models/concerns/effective_cpd_user.rb
221
224
  - app/models/effective/cpd_activity.rb
@@ -264,6 +267,7 @@ files:
264
267
  - app/views/admin/cpd_cycles/_form_cpd_special_rules.html.haml
265
268
  - app/views/admin/cpd_special_rules/_form.html.haml
266
269
  - app/views/admin/cpd_statements/_cpd_statement.html.haml
270
+ - app/views/admin/users/_form_cpd.html.haml
267
271
  - app/views/effective/cpd/_dashboard.html.haml
268
272
  - app/views/effective/cpd_audit_level_questions/_cpd_audit_level_question.html.haml
269
273
  - app/views/effective/cpd_audit_responses/_cpd_audit_response.html.haml