effective_cpd 0.0.1 → 0.1
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.
- checksums.yaml +4 -4
- data/README.md +89 -10
- data/app/controllers/admin/cpd_audit_level_questions_controller.rb +13 -0
- data/app/controllers/admin/cpd_audit_levels_controller.rb +13 -0
- data/app/controllers/admin/cpd_audit_reviews_controller.rb +13 -0
- data/app/controllers/admin/cpd_audits_controller.rb +41 -0
- data/app/controllers/effective/cpd_audit_reviews_controller.rb +60 -0
- data/app/controllers/effective/cpd_audits_controller.rb +55 -0
- data/app/controllers/effective/cpd_cycles_controller.rb +1 -0
- data/app/controllers/effective/cpd_statements_controller.rb +1 -3
- data/app/datatables/admin/effective_cpd_audit_level_questions_datatable.rb +30 -0
- data/app/datatables/admin/effective_cpd_audit_levels_datatable.rb +34 -0
- data/app/datatables/admin/effective_cpd_audit_reviews_datatable.rb +29 -0
- data/app/datatables/admin/effective_cpd_audits_datatable.rb +67 -0
- data/app/datatables/admin/effective_cpd_statements_datatable.rb +3 -3
- data/app/datatables/effective_cpd_available_audit_reviews_datatable.rb +37 -0
- data/app/datatables/effective_cpd_available_audits_datatable.rb +30 -0
- data/app/datatables/{effective_cpd_datatable.rb → effective_cpd_available_cycles_datatable.rb} +3 -4
- data/app/datatables/effective_cpd_completed_audit_reviews_datatable.rb +32 -0
- data/app/datatables/effective_cpd_completed_audits_datatable.rb +24 -0
- data/app/datatables/effective_cpd_completed_statements_datatable.rb +28 -0
- data/app/helpers/effective_cpd_audits_helper.rb +48 -0
- data/app/mailers/effective/cpd_mailer.rb +155 -3
- data/app/models/effective/cpd_activity.rb +16 -3
- data/app/models/effective/cpd_audit.rb +380 -0
- data/app/models/effective/cpd_audit_level.rb +87 -0
- data/app/models/effective/cpd_audit_level_question.rb +91 -0
- data/app/models/effective/cpd_audit_level_question_option.rb +34 -0
- data/app/models/effective/cpd_audit_level_section.rb +50 -0
- data/app/models/effective/cpd_audit_response.rb +86 -0
- data/app/models/effective/cpd_audit_response_option.rb +6 -0
- data/app/models/effective/cpd_audit_review.rb +222 -0
- data/app/models/effective/cpd_audit_review_item.rb +34 -0
- data/app/models/effective/cpd_category.rb +12 -3
- data/app/models/effective/cpd_cycle.rb +7 -0
- data/app/models/effective/cpd_rule.rb +3 -1
- data/app/models/effective/cpd_statement.rb +15 -8
- data/app/views/admin/cpd_activities/_form.html.haml +1 -1
- data/app/views/admin/cpd_audit_level_questions/_form.html.haml +100 -0
- data/app/views/admin/cpd_audit_levels/_form.html.haml +24 -0
- data/app/views/admin/cpd_audit_levels/_form_content_audit.html.haml +15 -0
- data/app/views/admin/cpd_audit_levels/_form_content_audit_review.html.haml +15 -0
- data/app/views/admin/cpd_audit_levels/_form_cpd_audit_level.html.haml +52 -0
- data/app/views/admin/cpd_audit_levels/_form_cpd_audit_level_section.html.haml +10 -0
- data/app/views/admin/cpd_audit_reviews/_cpd_audit_review.html.haml +1 -0
- data/app/views/admin/cpd_audit_reviews/_form.html.haml +13 -0
- data/app/views/admin/cpd_audits/_audit_reviewer_fields.html.haml +2 -0
- data/app/views/admin/cpd_audits/_auditee_fields.html.haml +2 -0
- data/app/views/admin/cpd_audits/_form.html.haml +46 -0
- data/app/views/admin/cpd_audits/_form_conflict.html.haml +24 -0
- data/app/views/admin/cpd_audits/_form_determination.html.haml +10 -0
- data/app/views/admin/cpd_audits/_form_exemption.html.haml +24 -0
- data/app/views/admin/cpd_audits/_form_extension.html.haml +24 -0
- data/app/views/admin/cpd_audits/_form_new.html.haml +28 -0
- data/app/views/admin/cpd_audits/_status.html.haml +121 -0
- data/app/views/admin/cpd_categories/_form.html.haml +1 -1
- data/app/views/admin/cpd_cycles/_form.html.haml +4 -4
- data/app/views/admin/cpd_cycles/_form_cpd_cycle.html.haml +3 -0
- data/app/views/admin/cpd_statements/_cpd_statement.html.haml +7 -0
- data/app/views/effective/cpd_audit_level_questions/_cpd_audit_level_question.html.haml +5 -0
- data/app/views/effective/cpd_audit_responses/_cpd_audit_response.html.haml +4 -0
- data/app/views/effective/cpd_audit_responses/_fields.html.haml +13 -0
- data/app/views/effective/cpd_audit_responses/fields/_choose_one.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_date.html.haml +2 -0
- data/app/views/effective/cpd_audit_responses/fields/_email.html.haml +2 -0
- data/app/views/effective/cpd_audit_responses/fields/_long_answer.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_number.html.haml +2 -0
- data/app/views/effective/cpd_audit_responses/fields/_select_all_that_apply.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_select_up_to_1.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_select_up_to_2.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_select_up_to_3.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_select_up_to_4.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_select_up_to_5.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_short_answer.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/fields/_upload_file.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_choose_one.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_date.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_email.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_long_answer.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_number.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_select_all_that_apply.html.haml +5 -0
- data/app/views/effective/cpd_audit_responses/responses/_select_up_to_1.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_select_up_to_2.html.haml +5 -0
- data/app/views/effective/cpd_audit_responses/responses/_select_up_to_3.html.haml +5 -0
- data/app/views/effective/cpd_audit_responses/responses/_select_up_to_4.html.haml +5 -0
- data/app/views/effective/cpd_audit_responses/responses/_select_up_to_5.html.haml +5 -0
- data/app/views/effective/cpd_audit_responses/responses/_short_answer.html.haml +1 -0
- data/app/views/effective/cpd_audit_responses/responses/_upload_file.html.haml +4 -0
- data/app/views/effective/cpd_audit_review_items/_cpd_audit_review_item.html.haml +6 -0
- data/app/views/effective/cpd_audit_review_items/_fields.html.haml +11 -0
- data/app/views/effective/cpd_audit_reviews/_conflict.html.haml +15 -0
- data/app/views/effective/cpd_audit_reviews/_cpd_audit_level_section.html.haml +23 -0
- data/app/views/effective/cpd_audit_reviews/_cpd_audit_review.html.haml +17 -0
- data/app/views/effective/cpd_audit_reviews/_cpd_statement.html.haml +15 -0
- data/app/views/effective/cpd_audit_reviews/_layout.html.haml +24 -0
- data/app/views/effective/cpd_audit_reviews/_recommendation.html.haml +9 -0
- data/app/views/effective/cpd_audit_reviews/_summary.html.haml +47 -0
- data/app/views/effective/cpd_audit_reviews/complete.html.haml +20 -0
- data/app/views/effective/cpd_audit_reviews/conflict.html.haml +21 -0
- data/app/views/effective/cpd_audit_reviews/cpd_audit_level_section.html.haml +43 -0
- data/app/views/effective/cpd_audit_reviews/cpd_statement.html.haml +35 -0
- data/app/views/effective/cpd_audit_reviews/information.html.haml +5 -0
- data/app/views/effective/cpd_audit_reviews/instructions.html.haml +10 -0
- data/app/views/effective/cpd_audit_reviews/questionnaire.html.haml +8 -0
- data/app/views/effective/cpd_audit_reviews/recommendation.html.haml +21 -0
- data/app/views/effective/cpd_audit_reviews/start.html.haml +10 -0
- data/app/views/effective/cpd_audit_reviews/statements.html.haml +29 -0
- data/app/views/effective/cpd_audit_reviews/submit.html.haml +14 -0
- data/app/views/effective/cpd_audit_reviews/waiting.html.haml +9 -0
- data/app/views/effective/cpd_audits/_conflict.html.haml +15 -0
- data/app/views/effective/cpd_audits/_cpd_audit.html.haml +12 -0
- data/app/views/effective/cpd_audits/_cpd_audit_level_section.html.haml +14 -0
- data/app/views/effective/cpd_audits/_exemption.html.haml +26 -0
- data/app/views/effective/cpd_audits/_extension.html.haml +30 -0
- data/app/views/effective/cpd_audits/_files.html.haml +12 -0
- data/app/views/effective/cpd_audits/_layout.html.haml +33 -0
- data/app/views/effective/cpd_audits/_summary.html.haml +54 -0
- data/app/views/effective/cpd_audits/_waiting.html.haml +6 -0
- data/app/views/effective/cpd_audits/complete.html.haml +24 -0
- data/app/views/effective/cpd_audits/conflict.html.haml +22 -0
- data/app/views/effective/cpd_audits/cpd_audit_level_section.html.haml +20 -0
- data/app/views/effective/cpd_audits/exemption.html.haml +19 -0
- data/app/views/effective/cpd_audits/extension.html.haml +21 -0
- data/app/views/effective/cpd_audits/files.html.haml +7 -0
- data/app/views/effective/cpd_audits/information.html.haml +5 -0
- data/app/views/effective/cpd_audits/instructions.html.haml +5 -0
- data/app/views/effective/cpd_audits/questionnaire.html.haml +5 -0
- data/app/views/effective/cpd_audits/start.html.haml +11 -0
- data/app/views/effective/cpd_audits/submit.html.haml +15 -0
- data/app/views/effective/cpd_audits/waiting.html.haml +24 -0
- data/app/views/effective/cpd_mailer/README.md +1 -0
- data/app/views/effective/cpd_mailer/cpd_audit_closed.liquid +15 -0
- data/app/views/effective/cpd_mailer/cpd_audit_conflict_resolved.liquid +15 -0
- data/app/views/effective/cpd_mailer/cpd_audit_conflicted.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_exemption_denied.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_exemption_granted.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_exemption_request.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_extension_denied.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_extension_granted.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_extension_request.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_opened.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_review_opened.liquid +15 -0
- data/app/views/effective/cpd_mailer/cpd_audit_review_ready.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_review_submitted.liquid +11 -0
- data/app/views/effective/cpd_mailer/cpd_audit_reviewed.liquid +13 -0
- data/app/views/effective/cpd_mailer/cpd_audit_submitted.liquid +13 -0
- data/app/views/effective/cpd_statement_activities/_cpd_statement_activity.html.haml +65 -0
- data/app/views/effective/cpd_statement_activities/_form.html.haml +9 -10
- data/app/views/effective/cpd_statements/_activities.html.haml +3 -64
- data/app/views/effective/cpd_statements/_activities_edit.html.haml +2 -0
- data/app/views/effective/cpd_statements/_activities_table.html.haml +64 -0
- data/app/views/effective/cpd_statements/_agreements.html.haml +19 -5
- data/app/views/effective/cpd_statements/_cpd_statement.html.haml +6 -3
- data/app/views/effective/cpd_statements/_summary.html.haml +26 -31
- data/app/views/effective/cpd_statements/activities.html.haml +1 -1
- data/app/views/effective/cpd_statements/agreements.html.haml +7 -1
- data/app/views/effective/cpd_statements/submit.html.haml +1 -1
- data/config/effective_cpd.rb +47 -10
- data/config/routes.rb +18 -1
- data/db/migrate/01_create_effective_cpd.rb.erb +157 -1
- data/db/seeds.rb +2 -1
- data/lib/effective_cpd.rb +42 -3
- data/lib/effective_cpd/version.rb +1 -1
- data/lib/generators/effective_cpd/install_generator.rb +16 -3
- metadata +168 -9
- data/app/datatables/effective_cpd_statements_datatable.rb +0 -23
- data/app/views/admin/cpd_statements/_form.html.haml +0 -6
|
@@ -3,10 +3,13 @@ module Effective
|
|
|
3
3
|
belongs_to :cpd_category
|
|
4
4
|
|
|
5
5
|
has_rich_text :body
|
|
6
|
-
log_changes(to: :cpd_category) if respond_to?(:log_changes)
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
if respond_to?(:log_changes)
|
|
8
|
+
log_changes(to: :cpd_category, except: [:cpd_statement_activities])
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
#has_many :rules, class_name: 'Effective::CpdRule', as: :ruleable
|
|
12
|
+
has_many :cpd_statement_activities
|
|
10
13
|
|
|
11
14
|
effective_resource do
|
|
12
15
|
title :string
|
|
@@ -33,9 +36,19 @@ module Effective
|
|
|
33
36
|
validates :title, presence: true
|
|
34
37
|
validates :position, presence: true
|
|
35
38
|
|
|
39
|
+
before_destroy do
|
|
40
|
+
if (count = cpd_statement_activities.length) > 0
|
|
41
|
+
raise("#{count} statement activities belong to this activity")
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
36
45
|
def to_s
|
|
37
46
|
title.presence || 'activity'
|
|
38
47
|
end
|
|
39
48
|
|
|
49
|
+
def amount_static?
|
|
50
|
+
amount_label.blank? && amount2_label.blank?
|
|
51
|
+
end
|
|
52
|
+
|
|
40
53
|
end
|
|
41
54
|
end
|
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
module Effective
|
|
2
|
+
class CpdAudit < ActiveRecord::Base
|
|
3
|
+
attr_accessor :current_user
|
|
4
|
+
attr_accessor :current_step
|
|
5
|
+
|
|
6
|
+
attr_accessor :admin_process_request
|
|
7
|
+
ADMIN_PROCESS_REQUEST_OPTIONS = ['Granted', 'Denied']
|
|
8
|
+
|
|
9
|
+
belongs_to :cpd_audit_level
|
|
10
|
+
belongs_to :user, polymorphic: true # The user being audited
|
|
11
|
+
|
|
12
|
+
has_many :cpd_audit_reviews, -> { order(:id) }, inverse_of: :cpd_audit, dependent: :destroy
|
|
13
|
+
accepts_nested_attributes_for :cpd_audit_reviews, allow_destroy: true
|
|
14
|
+
|
|
15
|
+
has_many :cpd_audit_responses, -> { order(:id) }, inverse_of: :cpd_audit, dependent: :destroy
|
|
16
|
+
accepts_nested_attributes_for :cpd_audit_responses
|
|
17
|
+
|
|
18
|
+
has_many_attached :files
|
|
19
|
+
|
|
20
|
+
if respond_to?(:log_changes)
|
|
21
|
+
log_changes(except: [:wizard_steps, :cpd_audit_reviews])
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
acts_as_email_form
|
|
25
|
+
acts_as_tokened
|
|
26
|
+
|
|
27
|
+
COMPLETED_STATES = [:exemption_granted, :closed]
|
|
28
|
+
|
|
29
|
+
WAITING_ON_ADMIN_STATES = [:conflicted, :exemption_requested, :extension_requested, :reviewed]
|
|
30
|
+
WAITING_ON_REVIEWERS_STATES = [:submitted]
|
|
31
|
+
WAITING_ON_AUDITEE_STATES = [:opened, :started, :conflicted_resolved, :exemption_denied, :extension_granted, :extension_denied]
|
|
32
|
+
|
|
33
|
+
acts_as_statused(
|
|
34
|
+
:opened, # Just Opened
|
|
35
|
+
:started, # First screen clicked
|
|
36
|
+
:conflicted, # Auditee has declared a conflict of interest
|
|
37
|
+
:conflicted_resolved, # The conflict of interest has been resolved
|
|
38
|
+
:exemption_requested, # Auditee has requested an exemption
|
|
39
|
+
:exemption_granted, # Exemption granted -> Audit is cancelled. Exit state.
|
|
40
|
+
:exemption_denied, # Exemption denied
|
|
41
|
+
:extension_requested, # Audittee has requested an extension
|
|
42
|
+
:extension_granted, # Extension granted
|
|
43
|
+
:extension_denied, # Extension denied
|
|
44
|
+
:submitted, # Audittee has completed questionnaire submitted. Audittee is done.
|
|
45
|
+
:reviewed, # All audit reviews completed. Ready for a determination.
|
|
46
|
+
:closed # Determination made by admin and/or audit committee. Exit state. All done.
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
acts_as_wizard(
|
|
50
|
+
start: 'Start',
|
|
51
|
+
information: 'Information',
|
|
52
|
+
instructions: 'Instructions',
|
|
53
|
+
|
|
54
|
+
# These 4 steps are determined by audit_level settings
|
|
55
|
+
conflict: 'Conflict of Interest',
|
|
56
|
+
exemption: 'Request Exemption',
|
|
57
|
+
extension: 'Request Extension',
|
|
58
|
+
waiting: 'Waiting',
|
|
59
|
+
|
|
60
|
+
questionnaire: 'Questionnaire',
|
|
61
|
+
# ... There will be one step per cpd_audit_level_sections here
|
|
62
|
+
files: 'Upload Resume',
|
|
63
|
+
|
|
64
|
+
submit: 'Confirm & Submit',
|
|
65
|
+
complete: 'Complete'
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
effective_resource do
|
|
69
|
+
due_date :date # Computed due date based on notification and extension date
|
|
70
|
+
|
|
71
|
+
# Important dates
|
|
72
|
+
notification_date :date # Can be set on CpdAudits#new, but basically created_at
|
|
73
|
+
extension_date :date # set by admin if extension if granted
|
|
74
|
+
|
|
75
|
+
# Final determination
|
|
76
|
+
determination :string
|
|
77
|
+
|
|
78
|
+
# Auditee response
|
|
79
|
+
conflict_of_interest :boolean
|
|
80
|
+
conflict_of_interest_reason :text
|
|
81
|
+
|
|
82
|
+
exemption_request :boolean
|
|
83
|
+
exemption_request_reason :text
|
|
84
|
+
|
|
85
|
+
extension_request :boolean
|
|
86
|
+
extension_request_date :date
|
|
87
|
+
extension_request_reason :text
|
|
88
|
+
|
|
89
|
+
# acts_as_statused
|
|
90
|
+
status :string
|
|
91
|
+
status_steps :text
|
|
92
|
+
|
|
93
|
+
# Status dates
|
|
94
|
+
started_at :datetime
|
|
95
|
+
submitted_at :datetime
|
|
96
|
+
reviewed_at :datetime
|
|
97
|
+
audited_at :datetime # TODO: CHange to closed_at
|
|
98
|
+
|
|
99
|
+
# Acts as tokened
|
|
100
|
+
token :string
|
|
101
|
+
|
|
102
|
+
# Acts as Wizard
|
|
103
|
+
wizard_steps :text
|
|
104
|
+
|
|
105
|
+
timestamps
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
scope :deep, -> { includes(:cpd_audit_level, user: [:cpd_statements], cpd_audit_reviews: [:cpd_audit_level, :user, :cpd_audit_review_items]) }
|
|
109
|
+
scope :sorted, -> { order(:id) }
|
|
110
|
+
|
|
111
|
+
scope :draft, -> { where(submitted_at: nil) }
|
|
112
|
+
scope :available, -> { where.not(status: COMPLETED_STATES) }
|
|
113
|
+
scope :completed, -> { where(status: COMPLETED_STATES) }
|
|
114
|
+
|
|
115
|
+
scope :waiting_on_admin, -> { where(status: WAITING_ON_ADMIN_STATES) }
|
|
116
|
+
scope :waiting_on_auditee, -> { where(status: WAITING_ON_AUDITEE_STATES) }
|
|
117
|
+
scope :waiting_on_reviewers, -> { where(status: WAITING_ON_REVIEWERS_STATES) }
|
|
118
|
+
|
|
119
|
+
before_validation(if: -> { new_record? }) do
|
|
120
|
+
self.notification_date ||= Time.zone.now
|
|
121
|
+
self.due_date ||= deadline_to_submit()
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
validates :notification_date, presence: true
|
|
125
|
+
validates :determination, presence: true, if: -> { closed? }
|
|
126
|
+
|
|
127
|
+
validates :conflict_of_interest_reason, presence: true, if: -> { conflict_of_interest? }
|
|
128
|
+
validates :exemption_request_reason, presence: true, if: -> { exemption_request? }
|
|
129
|
+
validates :extension_request_date, presence: true, if: -> { extension_request? }
|
|
130
|
+
validates :extension_request_reason, presence: true, if: -> { extension_request? }
|
|
131
|
+
|
|
132
|
+
validate(if: -> { determination.present? }) do
|
|
133
|
+
unless cpd_audit_level.determinations.include?(determination)
|
|
134
|
+
self.errors.add(:determination, 'must exist in this audit level')
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# If we're submitted. Check if we can go into reviewed?
|
|
139
|
+
before_save(if: -> { submitted? }) { review! }
|
|
140
|
+
|
|
141
|
+
after_commit(on: :create) do
|
|
142
|
+
send_email(:cpd_audit_opened)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def to_s
|
|
146
|
+
persisted? ? "#{cpd_audit_level} Audit of #{user}" : 'audit'
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
acts_as_wizard(
|
|
150
|
+
start: 'Start',
|
|
151
|
+
information: 'Information',
|
|
152
|
+
instructions: 'Instructions',
|
|
153
|
+
|
|
154
|
+
# These 4 steps are determined by audit_level settings
|
|
155
|
+
conflict: 'Conflict of Interest',
|
|
156
|
+
exemption: 'Request Exemption',
|
|
157
|
+
extension: 'Request Extension',
|
|
158
|
+
waiting: 'Waiting on Request',
|
|
159
|
+
|
|
160
|
+
questionaire: 'Questionaire',
|
|
161
|
+
# ... There will be one step per cpd_audit_level_sections here
|
|
162
|
+
files: 'Upload Resume',
|
|
163
|
+
|
|
164
|
+
submit: 'Confirm & Submit',
|
|
165
|
+
complete: 'Complete'
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def dynamic_wizard_steps
|
|
169
|
+
cpd_audit_level.cpd_audit_level_sections.each_with_object({}) do |section, h|
|
|
170
|
+
h["section#{section.position+1}".to_sym] = section.title
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def can_visit_step?(step)
|
|
175
|
+
return (step == :complete) if was_submitted? # Can only view complete step once submitted
|
|
176
|
+
can_revisit_completed_steps(step)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def required_steps
|
|
180
|
+
steps = [:start, :information, :instructions]
|
|
181
|
+
|
|
182
|
+
steps << :conflict if cpd_audit_level.conflict_of_interest?
|
|
183
|
+
|
|
184
|
+
if conflicted?
|
|
185
|
+
return steps + [:waiting, :submit, :complete]
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
steps << :exemption if cpd_audit_level.can_request_exemption?
|
|
189
|
+
|
|
190
|
+
unless exemption_requested?
|
|
191
|
+
steps << :extension if cpd_audit_level.can_request_extension?
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
if exemption_requested? || extension_requested?
|
|
195
|
+
steps += [:waiting]
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
steps += [:questionnaire] + dynamic_wizard_steps.keys + [:files, :submit, :complete]
|
|
199
|
+
|
|
200
|
+
steps
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def wizard_step_title(step)
|
|
204
|
+
WIZARD_STEPS[step] || dynamic_wizard_steps.fetch(step)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def deadline_date
|
|
208
|
+
(extension_date || notification_date)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def completed?
|
|
212
|
+
COMPLETED_STATES.include?(status.to_sym)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def in_progress?
|
|
216
|
+
COMPLETED_STATES.include?(status.to_sym) == false
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def cpd_audit_level_section(wizard_step)
|
|
220
|
+
position = (wizard_step.to_s.split('section').last.to_i rescue false)
|
|
221
|
+
cpd_audit_level.cpd_audit_level_sections.find { |section| (section.position + 1) == position }
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
# Find or build
|
|
225
|
+
def cpd_audit_response(cpd_audit_level_question)
|
|
226
|
+
cpd_audit_response = cpd_audit_responses.find { |r| r.cpd_audit_level_question_id == cpd_audit_level_question.id }
|
|
227
|
+
cpd_audit_response ||= cpd_audit_responses.build(cpd_audit: self, cpd_audit_level_question: cpd_audit_level_question)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# Auditee wizard action
|
|
231
|
+
def start!
|
|
232
|
+
started!
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
# Auditee wizard action
|
|
236
|
+
def conflict!
|
|
237
|
+
return started! unless conflict_of_interest?
|
|
238
|
+
|
|
239
|
+
update!(status: :conflicted)
|
|
240
|
+
send_email(:cpd_audit_conflicted)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Admin action
|
|
244
|
+
def resolve_conflict!
|
|
245
|
+
wizard_steps[:conflict] = nil # Have them complete the conflict step again.
|
|
246
|
+
|
|
247
|
+
assign_attributes(conflict_of_interest: false, conflict_of_interest_reason: nil)
|
|
248
|
+
conflicted_resolved!
|
|
249
|
+
|
|
250
|
+
send_email(:cpd_audit_conflict_resolved)
|
|
251
|
+
true
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Auditee wizard action
|
|
255
|
+
def exemption!
|
|
256
|
+
return started! unless exemption_request?
|
|
257
|
+
|
|
258
|
+
update!(status: :exemption_requested)
|
|
259
|
+
send_email(:cpd_audit_exemption_request)
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Admin action
|
|
263
|
+
def process_exemption!
|
|
264
|
+
case admin_process_request
|
|
265
|
+
when 'Granted' then grant_exemption!
|
|
266
|
+
when 'Denied' then deny_exemption!
|
|
267
|
+
else
|
|
268
|
+
self.errors.add(:admin_process_request, "can't be blank"); save!
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def grant_exemption!
|
|
273
|
+
wizard_steps[:submit] ||= Time.zone.now
|
|
274
|
+
submitted! && exemption_granted!
|
|
275
|
+
send_email(:cpd_audit_exemption_granted)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def deny_exemption!
|
|
279
|
+
assign_attributes(exemption_request: false)
|
|
280
|
+
exemption_denied!
|
|
281
|
+
send_email(:cpd_audit_exemption_denied)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Auditee wizard action
|
|
285
|
+
def extension!
|
|
286
|
+
return started! unless extension_request?
|
|
287
|
+
|
|
288
|
+
update!(status: :extension_requested)
|
|
289
|
+
send_email(:cpd_audit_extension_request)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
# Admin action
|
|
293
|
+
def process_extension!
|
|
294
|
+
case admin_process_request
|
|
295
|
+
when 'Granted' then grant_extension!
|
|
296
|
+
when 'Denied' then deny_extension!
|
|
297
|
+
else
|
|
298
|
+
self.errors.add(:admin_process_request, "can't be blank"); save!
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def grant_extension!
|
|
303
|
+
self.extension_date = extension_request_date
|
|
304
|
+
self.due_date = deadline_to_submit()
|
|
305
|
+
|
|
306
|
+
cpd_audit_reviews.each { |cpd_audit_review| cpd_audit_review.extension_granted! }
|
|
307
|
+
extension_granted!
|
|
308
|
+
send_email(:cpd_audit_extension_granted)
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
def deny_extension!
|
|
312
|
+
assign_attributes(extension_request: false)
|
|
313
|
+
extension_denied!
|
|
314
|
+
send_email(:cpd_audit_extension_denied)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Auditee wizard action
|
|
318
|
+
def submit!
|
|
319
|
+
submitted!
|
|
320
|
+
cpd_audit_reviews.each { |cpd_audit_review| cpd_audit_review.ready! }
|
|
321
|
+
send_email(:cpd_audit_submitted)
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Called in a before_save. Intended for applicant_review to call in its submit! method
|
|
325
|
+
def review!
|
|
326
|
+
return false unless submitted?
|
|
327
|
+
return false unless cpd_audit_reviews.present? && cpd_audit_reviews.all?(&:completed?)
|
|
328
|
+
|
|
329
|
+
reviewed!
|
|
330
|
+
send_email(:cpd_audit_reviewed)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
# Admin action
|
|
334
|
+
def close!
|
|
335
|
+
closed!
|
|
336
|
+
send_email(:cpd_audit_closed)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def email_form_defaults(action)
|
|
340
|
+
{ from: EffectiveCpd.mailer_sender }
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def send_email(email)
|
|
344
|
+
EffectiveCpd.send_email(email, self, email_form_params) unless email_form_skip?
|
|
345
|
+
true
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def deadline_to_conflict_of_interest
|
|
349
|
+
return nil unless cpd_audit_level&.conflict_of_interest?
|
|
350
|
+
return nil unless cpd_audit_level.days_to_declare_conflict.present?
|
|
351
|
+
|
|
352
|
+
date = (notification_date || created_at || Time.zone.now)
|
|
353
|
+
EffectiveResources.advance_date(date, business_days: cpd_audit_level.days_to_declare_conflict)
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
def deadline_to_exemption
|
|
357
|
+
return nil unless cpd_audit_level&.can_request_exemption?
|
|
358
|
+
return nil unless cpd_audit_level.days_to_request_exemption.present?
|
|
359
|
+
|
|
360
|
+
date = (notification_date || created_at || Time.zone.now)
|
|
361
|
+
EffectiveResources.advance_date(date, business_days: cpd_audit_level.days_to_request_exemption)
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
def deadline_to_extension
|
|
365
|
+
return nil unless cpd_audit_level&.can_request_extension?
|
|
366
|
+
return nil unless cpd_audit_level.days_to_request_extension.present?
|
|
367
|
+
|
|
368
|
+
date = (notification_date || created_at || Time.zone.now)
|
|
369
|
+
EffectiveResources.advance_date(date, business_days: cpd_audit_level.days_to_request_extension)
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def deadline_to_submit
|
|
373
|
+
return nil unless cpd_audit_level&.days_to_submit.present?
|
|
374
|
+
|
|
375
|
+
date = (extension_date || notification_date || created_at || Time.zone.now)
|
|
376
|
+
EffectiveResources.advance_date(date, business_days: cpd_audit_level.days_to_submit)
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
end
|
|
380
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module Effective
|
|
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
|
+
|
|
86
|
+
end
|
|
87
|
+
end
|