effective_cpd 0.1.19 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/effective/cpd_audits_controller.rb +2 -0
- data/app/datatables/admin/effective_cpd_statements_datatable.rb +8 -2
- data/app/helpers/effective_cpd_helper.rb +5 -0
- data/app/mailers/effective/cpd_mailer.rb +139 -67
- data/app/models/concerns/effective_cpd_user.rb +4 -0
- data/app/models/effective/cpd_audit.rb +35 -20
- data/app/models/effective/cpd_audit_review.rb +1 -1
- data/app/models/effective/cpd_rule.rb +4 -2
- data/app/models/effective/cpd_scorer.rb +1 -1
- data/app/models/effective/cpd_statement.rb +4 -4
- data/app/models/effective/cpd_statement_activity.rb +6 -6
- data/app/views/effective/cpd_audits/_cpd.html.haml +13 -0
- data/app/views/effective/cpd_audits/_layout.html.haml +1 -1
- data/app/views/effective/cpd_audits/conflict.html.haml +2 -1
- data/app/views/effective/cpd_audits/cpd.html.haml +19 -0
- data/app/views/effective/cpd_audits/exemption.html.haml +2 -1
- data/app/views/effective/cpd_audits/extension.html.haml +2 -1
- data/app/views/effective/cpd_statement_activities/_cpd_statement_activity.html.haml +5 -5
- data/app/views/effective/cpd_statement_activities/_form.html.haml +5 -5
- data/app/views/effective/cpd_statements/_activities_new.html.haml +1 -1
- data/app/views/effective/cpd_statements/_activities_table.html.haml +6 -6
- data/app/views/effective/cpd_statements/_layout.html.haml +3 -3
- data/app/views/effective/cpd_statements/_summary.html.haml +2 -2
- data/config/effective_cpd.rb +16 -22
- data/config/routes.rb +1 -1
- data/db/migrate/01_create_effective_cpd.rb.erb +6 -6
- data/lib/effective_cpd/version.rb +1 -1
- data/lib/effective_cpd.rb +2 -31
- metadata +4 -3
- data/app/views/layouts/effective_cpd_mailer_layout.html.haml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9940c548d939b8c1a285db0e19877bd4ed2147001fbebc947aaf6e02d548def6
|
4
|
+
data.tar.gz: 0547a9982f49587cbe07f2d3b65b6ab0da31be1728d7a55541cebd48cb560dde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bc621cc69009ae0a6629d11f07b8fcabcbf9aafe011649b441d096e90754938104b24c5633b0b7374f298b005d4e558a2f6ebcdca1c19b2b442883d4a7e3e018
|
7
|
+
data.tar.gz: dca45ea584ab120514a7fb2d4231d2d19bcd373f84066e16ad57af2d05b46e605e7692d22e6e18c46913a3af233022dbac597672cacf337d7d350e80ae0b9030
|
@@ -32,6 +32,8 @@ module Effective
|
|
32
32
|
when :extension
|
33
33
|
params.require(:effective_cpd_audit)
|
34
34
|
.permit(:current_step, :extension_request, :extension_request_date, :extension_request_reason)
|
35
|
+
when :cpd
|
36
|
+
params.require(:effective_cpd_audit).permit(:current_step)
|
35
37
|
when :questionnaire
|
36
38
|
params.require(:effective_cpd_audit).permit(:current_step)
|
37
39
|
when :files
|
@@ -17,8 +17,14 @@ module Admin
|
|
17
17
|
col :cpd_cycle, label: cpd_cycle_label.titleize
|
18
18
|
col :user
|
19
19
|
col :submitted_at, as: :date, label: 'Submitted'
|
20
|
-
|
21
|
-
col :
|
20
|
+
|
21
|
+
col :score do |cpd_statement|
|
22
|
+
cpd_score(cpd_statement.score)
|
23
|
+
end
|
24
|
+
|
25
|
+
col :carry_forward do |cpd_statement|
|
26
|
+
cpd_score(cpd_statement.carry_forward)
|
27
|
+
end
|
22
28
|
|
23
29
|
actions_col
|
24
30
|
end
|
@@ -1,122 +1,194 @@
|
|
1
1
|
module Effective
|
2
2
|
class CpdMailer < EffectiveCpd.parent_mailer_class
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
include EffectiveMailer
|
5
|
+
include EffectiveEmailTemplatesMailer if EffectiveCpd.use_effective_email_templates
|
5
6
|
|
6
7
|
# CPD Audit
|
7
|
-
def cpd_audit_opened(
|
8
|
-
|
9
|
-
|
8
|
+
def cpd_audit_opened(resource, opts = {})
|
9
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
10
|
+
|
11
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_url(resource))
|
12
|
+
@cpd_audit = resource
|
13
|
+
|
14
|
+
subject = subject_for(__method__, 'CPD Audit Opened', resource, opts)
|
15
|
+
headers = headers_for(resource, opts)
|
10
16
|
|
11
|
-
mail(to:
|
17
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
12
18
|
end
|
13
19
|
|
14
|
-
def cpd_audit_conflicted(
|
15
|
-
|
16
|
-
|
20
|
+
def cpd_audit_conflicted(resource, opts = {})
|
21
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
22
|
+
|
23
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.edit_admin_cpd_audit_url(resource))
|
24
|
+
@cpd_audit = resource
|
25
|
+
|
26
|
+
subject = subject_for(__method__, 'CPD Audit Conflicted', resource, opts)
|
27
|
+
headers = headers_for(resource, opts)
|
17
28
|
|
18
|
-
mail(to:
|
29
|
+
mail(to: mailer_admin, subject: subject, **headers)
|
19
30
|
end
|
20
31
|
|
21
|
-
def cpd_audit_conflict_resolved(
|
22
|
-
|
23
|
-
@assigns.merge!(url: effective_cpd.cpd_audit_url(cpd_audit))
|
32
|
+
def cpd_audit_conflict_resolved(resource, opts = {})
|
33
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
24
34
|
|
25
|
-
|
35
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_url(resource))
|
36
|
+
@cpd_audit = resource
|
37
|
+
|
38
|
+
subject = subject_for(__method__, 'CPD Audit Conflict Resolved', resource, opts)
|
39
|
+
headers = headers_for(resource, opts)
|
40
|
+
|
41
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
26
42
|
end
|
27
43
|
|
28
|
-
def cpd_audit_exemption_request(
|
29
|
-
|
30
|
-
|
44
|
+
def cpd_audit_exemption_request(resource, opts = {})
|
45
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
46
|
+
|
47
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.edit_admin_cpd_audit_url(resource))
|
48
|
+
@cpd_audit = resource
|
49
|
+
|
50
|
+
subject = subject_for(__method__, 'CPD Audit Exemption Request', resource, opts)
|
51
|
+
headers = headers_for(resource, opts)
|
31
52
|
|
32
|
-
mail(to:
|
53
|
+
mail(to: mailer_admin, subject: subject, **headers)
|
33
54
|
end
|
34
55
|
|
35
|
-
def cpd_audit_exemption_denied(
|
36
|
-
|
37
|
-
@assigns.merge!(url: effective_cpd.cpd_audit_url(cpd_audit))
|
56
|
+
def cpd_audit_exemption_denied(resource, opts = {})
|
57
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
38
58
|
|
39
|
-
|
59
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_url(resource))
|
60
|
+
@cpd_audit = resource
|
61
|
+
|
62
|
+
subject = subject_for(__method__, 'CPD Audit Exemption Denied', resource, opts)
|
63
|
+
headers = headers_for(resource, opts)
|
64
|
+
|
65
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
40
66
|
end
|
41
67
|
|
42
|
-
def cpd_audit_exemption_granted(
|
43
|
-
|
44
|
-
|
68
|
+
def cpd_audit_exemption_granted(resource, opts = {})
|
69
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
70
|
+
|
71
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_url(resource))
|
72
|
+
@cpd_audit = resource
|
73
|
+
|
74
|
+
subject = subject_for(__method__, 'CPD Audit Exemption Granted', resource, opts)
|
75
|
+
headers = headers_for(resource, opts)
|
45
76
|
|
46
|
-
mail(to:
|
77
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
47
78
|
end
|
48
79
|
|
49
|
-
def cpd_audit_extension_request(
|
50
|
-
|
51
|
-
@assigns.merge!(url: effective_cpd.edit_admin_cpd_audit_url(cpd_audit))
|
80
|
+
def cpd_audit_extension_request(resource, opts = {})
|
81
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
52
82
|
|
53
|
-
|
83
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.edit_admin_cpd_audit_url(resource))
|
84
|
+
@cpd_audit = resource
|
85
|
+
|
86
|
+
subject = subject_for(__method__, 'CPD Audit Extension Request', resource, opts)
|
87
|
+
headers = headers_for(resource, opts)
|
88
|
+
|
89
|
+
mail(to: mailer_admin, subject: subject, **headers)
|
54
90
|
end
|
55
91
|
|
56
|
-
def cpd_audit_extension_denied(
|
57
|
-
|
58
|
-
|
92
|
+
def cpd_audit_extension_denied(resource, opts = {})
|
93
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
94
|
+
|
95
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_url(resource))
|
96
|
+
@cpd_audit = resource
|
97
|
+
|
98
|
+
subject = subject_for(__method__, 'CPD Audit Extension Denied', resource, opts)
|
99
|
+
headers = headers_for(resource, opts)
|
59
100
|
|
60
|
-
mail(to:
|
101
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
61
102
|
end
|
62
103
|
|
63
|
-
def cpd_audit_extension_granted(
|
64
|
-
|
65
|
-
@assigns.merge!(url: effective_cpd.cpd_audit_url(cpd_audit))
|
104
|
+
def cpd_audit_extension_granted(resource, opts = {})
|
105
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
66
106
|
|
67
|
-
|
107
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_url(resource))
|
108
|
+
@cpd_audit = resource
|
109
|
+
|
110
|
+
subject = subject_for(__method__, 'CPD Audit Extension Granted', resource, opts)
|
111
|
+
headers = headers_for(resource, opts)
|
112
|
+
|
113
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
68
114
|
end
|
69
115
|
|
70
|
-
def cpd_audit_submitted(
|
71
|
-
|
72
|
-
|
116
|
+
def cpd_audit_submitted(resource, opts = {})
|
117
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
118
|
+
|
119
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.edit_admin_cpd_audit_url(resource))
|
120
|
+
@cpd_audit = resource
|
121
|
+
|
122
|
+
subject = subject_for(__method__, 'CPD Audit Submitted', resource, opts)
|
123
|
+
headers = headers_for(resource, opts)
|
73
124
|
|
74
|
-
mail(to:
|
125
|
+
mail(to: mailer_admin, subject: subject, **headers)
|
75
126
|
end
|
76
127
|
|
77
|
-
def cpd_audit_reviewed(
|
78
|
-
|
79
|
-
@assigns.merge!(url: effective_cpd.edit_admin_cpd_audit_url(cpd_audit))
|
128
|
+
def cpd_audit_reviewed(resource, opts = {})
|
129
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
80
130
|
|
81
|
-
|
131
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.edit_admin_cpd_audit_url(resource))
|
132
|
+
@cpd_audit = resource
|
133
|
+
|
134
|
+
subject = subject_for(__method__, 'CPD Audit Reviewed', resource, opts)
|
135
|
+
headers = headers_for(resource, opts)
|
136
|
+
|
137
|
+
mail(to: mailer_admin, subject: subject, **headers)
|
82
138
|
end
|
83
139
|
|
84
|
-
def cpd_audit_closed(
|
85
|
-
|
86
|
-
|
140
|
+
def cpd_audit_closed(resource, opts = {})
|
141
|
+
raise('expected an Effective::CpdAudit') unless resource.kind_of?(Effective::CpdAudit)
|
142
|
+
|
143
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_url(resource))
|
144
|
+
@cpd_audit = resource
|
145
|
+
|
146
|
+
subject = subject_for(__method__, 'CPD Audit Closed', resource, opts)
|
147
|
+
headers = headers_for(resource, opts)
|
87
148
|
|
88
|
-
mail(to:
|
149
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
89
150
|
end
|
90
151
|
|
91
152
|
# CPD Audit Review
|
92
|
-
def cpd_audit_review_opened(
|
93
|
-
|
94
|
-
@assigns.merge!(url: effective_cpd.cpd_audit_review_url(cpd_audit_review))
|
153
|
+
def cpd_audit_review_opened(resource, opts = {})
|
154
|
+
raise('expected an Effective::CpdAuditReview') unless resource.kind_of?(Effective::CpdAuditReview)
|
95
155
|
|
96
|
-
|
97
|
-
|
156
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_review_url(resource))
|
157
|
+
@cpd_audit_review = resource
|
98
158
|
|
99
|
-
|
100
|
-
|
101
|
-
@assigns.merge!(url: effective_cpd.cpd_audit_review_url(cpd_audit_review))
|
159
|
+
subject = subject_for(__method__, 'CPD Audit Review Opened', resource, opts)
|
160
|
+
headers = headers_for(resource, opts)
|
102
161
|
|
103
|
-
mail(to:
|
162
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
104
163
|
end
|
105
164
|
|
106
|
-
def
|
107
|
-
|
108
|
-
|
165
|
+
def cpd_audit_review_ready(resource, opts = {})
|
166
|
+
raise('expected an Effective::CpdAuditReview') unless resource.kind_of?(Effective::CpdAuditReview)
|
167
|
+
|
168
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_review_url(resource))
|
169
|
+
@cpd_audit_review = resource
|
109
170
|
|
110
|
-
|
171
|
+
subject = subject_for(__method__, 'CPD Audit Review Ready', resource, opts)
|
172
|
+
headers = headers_for(resource, opts)
|
173
|
+
|
174
|
+
mail(to: resource.user.email, subject: subject, **headers)
|
111
175
|
end
|
112
176
|
|
113
|
-
|
177
|
+
def cpd_audit_review_submitted(resource, opts = {})
|
178
|
+
raise('expected an Effective::CpdAuditReview') unless resource.kind_of?(Effective::CpdAuditReview)
|
114
179
|
|
115
|
-
|
116
|
-
|
180
|
+
@assigns = assigns_for(resource).merge(url: effective_cpd.edit_admin_cpd_audit_url(resource.cpd_audit))
|
181
|
+
@cpd_audit_review = resource
|
182
|
+
|
183
|
+
subject = subject_for(__method__, 'CPD Audit Review Submitted', resource, opts)
|
184
|
+
headers = headers_for(resource, opts)
|
185
|
+
|
186
|
+
mail(to: mailer_admin, subject: subject, **headers)
|
117
187
|
end
|
118
188
|
|
119
|
-
|
189
|
+
protected
|
190
|
+
|
191
|
+
def assigns_for(resource)
|
120
192
|
unless resource.kind_of?(Effective::CpdAudit) || resource.kind_of?(Effective::CpdAuditReview)
|
121
193
|
raise('expected an Effective::CpdAudit or Effective::CpdAuditReview')
|
122
194
|
end
|
@@ -56,6 +56,7 @@ module Effective
|
|
56
56
|
exemption: 'Request Exemption',
|
57
57
|
extension: 'Request Extension',
|
58
58
|
waiting: 'Waiting',
|
59
|
+
cpd: 'CPD',
|
59
60
|
|
60
61
|
questionnaire: 'Questionnaire',
|
61
62
|
# ... There will be one step per cpd_audit_level_sections here
|
@@ -129,6 +130,21 @@ module Effective
|
|
129
130
|
validates :extension_request_date, presence: true, if: -> { extension_request? }
|
130
131
|
validates :extension_request_reason, presence: true, if: -> { extension_request? }
|
131
132
|
|
133
|
+
validate(if: -> { current_step == :conflict && conflict_of_interest? }) do
|
134
|
+
deadline = deadline_to_conflict_of_interest()
|
135
|
+
self.errors.add(:base, 'deadline to declare conflict of interest has already passed') if deadline && deadline < Time.zone.now
|
136
|
+
end
|
137
|
+
|
138
|
+
validate(if: -> { current_step == :exemption && exemption_request? }) do
|
139
|
+
deadline = deadline_to_exemption()
|
140
|
+
self.errors.add(:base, 'deadline to request exemption has already passed') if deadline && deadline < Time.zone.now
|
141
|
+
end
|
142
|
+
|
143
|
+
validate(if: -> { current_step == :extension && extension_request? }) do
|
144
|
+
deadline = deadline_to_extension()
|
145
|
+
self.errors.add(:base, 'deadline to request extension has already passed') if deadline && deadline < Time.zone.now
|
146
|
+
end
|
147
|
+
|
132
148
|
validate(if: -> { determination.present? }) do
|
133
149
|
unless cpd_audit_level.determinations.include?(determination)
|
134
150
|
self.errors.add(:determination, 'must exist in this audit level')
|
@@ -146,25 +162,6 @@ module Effective
|
|
146
162
|
persisted? ? "#{cpd_audit_level} Audit of #{user}" : 'audit'
|
147
163
|
end
|
148
164
|
|
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
165
|
def dynamic_wizard_steps
|
169
166
|
cpd_audit_level.cpd_audit_level_sections.each_with_object({}) do |section, h|
|
170
167
|
h["section#{section.position+1}".to_sym] = section.title
|
@@ -195,7 +192,7 @@ module Effective
|
|
195
192
|
steps += [:waiting]
|
196
193
|
end
|
197
194
|
|
198
|
-
steps += [:questionnaire] + dynamic_wizard_steps.keys + [:files, :submit, :complete]
|
195
|
+
steps += [:cpd, :questionnaire] + dynamic_wizard_steps.keys + [:files, :submit, :complete]
|
199
196
|
|
200
197
|
steps
|
201
198
|
end
|
@@ -314,6 +311,24 @@ module Effective
|
|
314
311
|
send_email(:cpd_audit_extension_denied)
|
315
312
|
end
|
316
313
|
|
314
|
+
# Require CPD step
|
315
|
+
def user_cpd_required?
|
316
|
+
return false unless user.cpd_audit_cpd_required?
|
317
|
+
required_cpd_cycle.present?
|
318
|
+
end
|
319
|
+
|
320
|
+
def user_cpd_completed?
|
321
|
+
return true if required_cpd_cycle.blank?
|
322
|
+
user.cpd_statements.any? { |s| s.completed? && s.cpd_cycle_id == required_cpd_cycle.id }
|
323
|
+
end
|
324
|
+
|
325
|
+
def required_cpd_cycle
|
326
|
+
@required_cpd_cycle ||= begin
|
327
|
+
last_year = ((notification_date || created_at || Time.zone.now) - 1.year).all_year
|
328
|
+
Effective::CpdCycle.available.where(start_at: last_year).first
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
317
332
|
# Auditee wizard action
|
318
333
|
def submit!
|
319
334
|
submitted!
|
@@ -7,7 +7,7 @@ module Effective
|
|
7
7
|
belongs_to :cpd_audit_level
|
8
8
|
belongs_to :user, polymorphic: true # Auditor
|
9
9
|
|
10
|
-
has_many :cpd_audit_review_items, -> { CpdAuditReviewItem.sorted }, inverse_of: :cpd_audit_review
|
10
|
+
has_many :cpd_audit_review_items, -> { CpdAuditReviewItem.sorted }, inverse_of: :cpd_audit_review, dependent: :destroy
|
11
11
|
accepts_nested_attributes_for :cpd_audit_review_items, reject_if: :all_blank, allow_destroy: true
|
12
12
|
|
13
13
|
if respond_to?(:log_changes)
|
@@ -117,10 +117,12 @@ module Effective
|
|
117
117
|
private
|
118
118
|
|
119
119
|
def eval_equation(amount: nil, amount2: nil)
|
120
|
-
return 0 if formula.blank?
|
120
|
+
return BigDecimal(0) if formula.blank?
|
121
121
|
|
122
122
|
equation = formula.gsub('amount2', amount2.to_s).gsub('amount', amount.to_s)
|
123
|
-
|
123
|
+
|
124
|
+
# Returns a BigDecimal
|
125
|
+
eval(equation).to_d
|
124
126
|
end
|
125
127
|
|
126
128
|
end
|
@@ -103,7 +103,7 @@ module Effective
|
|
103
103
|
cpd_categories = special_rule.ruleables.select { |obj| obj.kind_of?(Effective::CpdCategory) }
|
104
104
|
|
105
105
|
max_credits_per_cycle = special_rule.max_credits_per_cycle
|
106
|
-
raise('expected max credits per cycle to be present') unless max_credits_per_cycle
|
106
|
+
raise('expected max credits per cycle to be present') unless (max_credits_per_cycle || 0) > 0
|
107
107
|
|
108
108
|
activities = statement.cpd_statement_activities.select { |sa| cpd_categories.include?(sa.cpd_category) }
|
109
109
|
|
@@ -97,17 +97,17 @@ module Effective
|
|
97
97
|
required_by_cycle = cpd_cycle&.required_score
|
98
98
|
required_by_user = user.cpd_statement_required_score(self) if user.respond_to?(:cpd_statement_required_score)
|
99
99
|
|
100
|
-
[required_by_cycle.
|
100
|
+
[required_by_cycle.to_d, required_by_user.to_d].max
|
101
101
|
end
|
102
102
|
|
103
103
|
def carry_forward
|
104
|
-
cpd_statement_activities.sum { |activity| activity.carry_forward
|
104
|
+
cpd_statement_activities.sum { |activity| activity.carry_forward || BigDecimal(0) }.to_d
|
105
105
|
end
|
106
106
|
|
107
107
|
# {category_id => 20, category_id => 15}
|
108
108
|
def score_per_category
|
109
|
-
@score_per_category ||= Hash.new(0).tap do |scores|
|
110
|
-
cpd_statement_activities.each { |activity| scores[activity.cpd_category_id] += activity.score.
|
109
|
+
@score_per_category ||= Hash.new(BigDecimal(0)).tap do |scores|
|
110
|
+
cpd_statement_activities.each { |activity| scores[activity.cpd_category_id] += activity.score.to_d }
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
@@ -16,14 +16,14 @@ module Effective
|
|
16
16
|
end
|
17
17
|
|
18
18
|
effective_resource do
|
19
|
-
amount :
|
20
|
-
amount2 :
|
19
|
+
amount :decimal
|
20
|
+
amount2 :decimal
|
21
21
|
|
22
22
|
description :text
|
23
23
|
|
24
|
-
carry_over :
|
25
|
-
score :
|
26
|
-
carry_forward :
|
24
|
+
carry_over :decimal # carry_over_from_last_cycle
|
25
|
+
score :decimal
|
26
|
+
carry_forward :decimal # carry_forward_to_next_cycle
|
27
27
|
|
28
28
|
reduced_messages :text
|
29
29
|
|
@@ -35,7 +35,7 @@ module Effective
|
|
35
35
|
scope :deep, -> { includes(:cpd_statement, :cpd_category, :cpd_activity, :original) }
|
36
36
|
scope :sorted, -> { order(:id) }
|
37
37
|
|
38
|
-
validates :original, presence: true, if: -> { carry_over
|
38
|
+
validates :original, presence: true, if: -> { (carry_over || 0) > 0 }
|
39
39
|
validates :description, presence: true
|
40
40
|
|
41
41
|
validate(if: -> { new_record? && cpd_statement.present? }) do
|
@@ -0,0 +1,13 @@
|
|
1
|
+
= card(cpd_audit.wizard_step_title(step)) do
|
2
|
+
- cpd_cycle = cpd_audit.required_cpd_cycle
|
3
|
+
|
4
|
+
%table.table
|
5
|
+
%tbody
|
6
|
+
%tr
|
7
|
+
%th CPD Requirements
|
8
|
+
%td
|
9
|
+
- if cpd_audit.user_cpd_required? == false
|
10
|
+
Not required
|
11
|
+
|
12
|
+
- if cpd_cycle.present?
|
13
|
+
= cpd_cycle
|
@@ -5,7 +5,8 @@
|
|
5
5
|
- resource.cpd_audit_reviews.each do |cpd_audit_review|
|
6
6
|
%li #{cpd_audit_review.user} <#{mail_to(cpd_audit_review.user.email)}>
|
7
7
|
|
8
|
-
|
8
|
+
- if resource.deadline_to_conflict_of_interest.present?
|
9
|
+
%p The deadline to declare a conflict of interest is: #{resource.deadline_to_conflict_of_interest.strftime('%F')}.
|
9
10
|
|
10
11
|
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
11
12
|
= f.hidden_field :current_step
|
@@ -0,0 +1,19 @@
|
|
1
|
+
= render('layout') do
|
2
|
+
- cpd_cycle = resource.required_cpd_cycle
|
3
|
+
|
4
|
+
- if resource.user_cpd_required? == false
|
5
|
+
%p You are not required to submit a CPD statement at this time.
|
6
|
+
- elsif resource.user_cpd_completed?
|
7
|
+
%p Thank you! You have submitted a CPD statement for the required #{cpd_cycle} year.
|
8
|
+
- elsif cpd_cycle.present?
|
9
|
+
%p You must submit a CPD statement for the #{cpd_cycle} year before you may continue.
|
10
|
+
|
11
|
+
- if cpd_cycle.present?
|
12
|
+
%p= link_to("#{cpd_cycle} Statement", effective_cpd.cpd_cycle_cpd_statement_build_path(cpd_cycle, :new, :start), class: 'btn btn-primary', target: '_blank')
|
13
|
+
|
14
|
+
- if (resource.user_cpd_required? == false || resource.user_cpd_completed?)
|
15
|
+
|
16
|
+
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
17
|
+
= f.hidden_field :current_step
|
18
|
+
|
19
|
+
= f.submit 'Save and Continue', center: true
|
@@ -2,7 +2,8 @@
|
|
2
2
|
- if resource.was_exemption_requested?
|
3
3
|
= render('effective/cpd_audits/exemption', cpd_audit: resource, step: :exemption)
|
4
4
|
|
5
|
-
|
5
|
+
- if resource.deadline_to_exemption.present?
|
6
|
+
%p The deadline to request an exemption is: #{resource.deadline_to_exemption.strftime('%F')}.
|
6
7
|
|
7
8
|
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
8
9
|
= f.hidden_field :current_step
|
@@ -2,7 +2,8 @@
|
|
2
2
|
- if resource.was_extension_requested?
|
3
3
|
= render('effective/cpd_audits/extension', cpd_audit: resource, step: :extension)
|
4
4
|
|
5
|
-
|
5
|
+
- if resource.deadline_to_extension.present?
|
6
|
+
%p The deadline to request an extension is: #{resource.deadline_to_extension.strftime('%F')}.
|
6
7
|
|
7
8
|
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
8
9
|
= f.hidden_field :current_step
|
@@ -24,12 +24,12 @@
|
|
24
24
|
.col
|
25
25
|
%strong= cpd_activity.amount_label
|
26
26
|
%br
|
27
|
-
= cpd_statement_activity.amount
|
27
|
+
= cpd_score(cpd_statement_activity.amount)
|
28
28
|
|
29
29
|
- if cpd_activity.amount2_label.present?
|
30
30
|
.col.text-center
|
31
31
|
%strong= cpd_activity.amount2_label
|
32
|
-
= cpd_statement_activity.amount2
|
32
|
+
= cpd_score(cpd_statement_activity.amount2)
|
33
33
|
|
34
34
|
- if cpd_activity.amount_static?
|
35
35
|
.col
|
@@ -43,14 +43,14 @@
|
|
43
43
|
%strong= cpd_credits_label.titleize
|
44
44
|
%br
|
45
45
|
- if cpd_statement_activity.reduced_messages.present?
|
46
|
-
%span{title: cpd_statement_activity.reduced_messages.values.join("\n\n")}= "#{cpd_statement_activity.score} *"
|
46
|
+
%span{title: cpd_statement_activity.reduced_messages.values.join("\n\n")}= "#{cpd_score(cpd_statement_activity.score)} *"
|
47
47
|
- else
|
48
|
-
= cpd_statement_activity.score
|
48
|
+
= cpd_score(cpd_statement_activity.score)
|
49
49
|
|
50
50
|
.col.text-center
|
51
51
|
%strong Carry
|
52
52
|
%br
|
53
|
-
= cpd_statement_activity.carry_forward
|
53
|
+
= cpd_score(cpd_statement_activity.carry_forward)
|
54
54
|
|
55
55
|
- if cpd_statement_activity.files.present?
|
56
56
|
%p
|
@@ -28,23 +28,23 @@
|
|
28
28
|
%strong= cpd_credits_label.titleize
|
29
29
|
%br
|
30
30
|
- if f.object.reduced_messages.present?
|
31
|
-
%span{title: f.object.reduced_messages.values.join("\n\n")}= "#{f.object.score} *"
|
31
|
+
%span{title: f.object.reduced_messages.values.join("\n\n")}= "#{cpd_score(f.object.score)} *"
|
32
32
|
- else
|
33
|
-
= f.object.score
|
33
|
+
= cpd_score(f.object.score)
|
34
34
|
|
35
35
|
.col-2.text-center
|
36
36
|
- if f.object.persisted?
|
37
37
|
%strong Carry Forward
|
38
38
|
%br
|
39
|
-
= f.object.carry_forward
|
39
|
+
= cpd_score(f.object.carry_forward)
|
40
40
|
|
41
41
|
.row
|
42
42
|
.col
|
43
43
|
- if activity.amount_label.present?
|
44
|
-
= f.
|
44
|
+
= f.float_field :amount, label: activity.amount_label, required: true
|
45
45
|
|
46
46
|
- if activity.amount2_label.present?
|
47
|
-
= f.
|
47
|
+
= f.float_field :amount2, label: activity.amount2_label, required: true
|
48
48
|
|
49
49
|
- if activity.amount_static?
|
50
50
|
= f.hidden_field :amount, value: 1
|
@@ -16,7 +16,7 @@
|
|
16
16
|
%h3
|
17
17
|
#{category}
|
18
18
|
%small
|
19
|
-
= cpd_statement.score_per_category[category.id]
|
19
|
+
= cpd_score(cpd_statement.score_per_category[category.id])
|
20
20
|
- if rule.max_credits_per_cycle.present?
|
21
21
|
= '/'
|
22
22
|
= rule.max_credits_per_cycle
|
@@ -41,12 +41,12 @@
|
|
41
41
|
|
42
42
|
.col-2.score
|
43
43
|
- if statement_activity.reduced_messages.present?
|
44
|
-
%span{title: statement_activity.reduced_messages.values.join("\n\n")}= "#{statement_activity.score} *"
|
44
|
+
%span{title: statement_activity.reduced_messages.values.join("\n\n")}= "#{cpd_score(statement_activity.score)} *"
|
45
45
|
- else
|
46
|
-
= statement_activity.score
|
46
|
+
= cpd_score(statement_activity.score)
|
47
47
|
|
48
48
|
.col-2.carry-forward
|
49
|
-
= statement_activity.carry_forward
|
49
|
+
= cpd_score(statement_activity.carry_forward)
|
50
50
|
|
51
51
|
.statement-activity-form.row{style: 'display: none;'}
|
52
52
|
.col
|
@@ -59,6 +59,6 @@
|
|
59
59
|
.col-8
|
60
60
|
%h4 Total #{cpd_credits_label} in statement
|
61
61
|
.col-2.score
|
62
|
-
%h4= cpd_statement.score
|
62
|
+
%h4= cpd_score(cpd_statement.score)
|
63
63
|
.col-2.carry-forward
|
64
|
-
%h4= cpd_statement.carry_forward
|
64
|
+
%h4= cpd_score(cpd_statement.carry_forward)
|
@@ -19,14 +19,14 @@
|
|
19
19
|
|
20
20
|
%tr
|
21
21
|
%td
|
22
|
-
%h4= resource.score.
|
22
|
+
%h4= cpd_score(resource.score.to_d)
|
23
23
|
|
24
24
|
%td
|
25
|
-
#{cpd_credits_label} out of #{resource.required_score} required
|
25
|
+
#{cpd_credits_label} out of #{resource.required_score.to_i} required
|
26
26
|
|
27
27
|
%tr
|
28
28
|
%td
|
29
|
-
%h4= last_3_scores.
|
29
|
+
%h4= cpd_score(last_3_scores.to_d)
|
30
30
|
|
31
31
|
%td #{cpd_credits_label} in last 3 #{cpd_cycles_label} (including this #{cpd_cycle_label})
|
32
32
|
|
data/config/effective_cpd.rb
CHANGED
@@ -42,27 +42,21 @@ EffectiveCpd.setup do |config|
|
|
42
42
|
# Audit Reviewer Scope Collection
|
43
43
|
config.audit_reviewer_user_scope = :all
|
44
44
|
|
45
|
-
# Mailer
|
45
|
+
# Mailer Settings
|
46
|
+
# Please see config/initializers/effective_resources.rb for default effective_* gem mailer settings
|
47
|
+
#
|
46
48
|
# Configure the class responsible to send e-mails.
|
47
|
-
# config.mailer = 'Effective::
|
48
|
-
|
49
|
-
#
|
50
|
-
#
|
51
|
-
|
52
|
-
#
|
53
|
-
# config.
|
54
|
-
|
55
|
-
# Default
|
56
|
-
config.
|
57
|
-
|
58
|
-
#
|
59
|
-
config.
|
60
|
-
|
61
|
-
# Send Admin correspondence To
|
62
|
-
config.mailer_admin = "admin@example.com"
|
63
|
-
|
64
|
-
# Will work with effective_email_templates gem:
|
65
|
-
# - The audit and audit review email content will be preopulated based off the template
|
66
|
-
# - Uses an EmailTemplatesMailer mailer instead of ActionMailer::Base for default parent_mailer
|
67
|
-
config.use_effective_email_templates = false
|
49
|
+
# config.mailer = 'Effective::EventsMailer'
|
50
|
+
#
|
51
|
+
# Override effective_resource mailer defaults
|
52
|
+
#
|
53
|
+
# config.parent_mailer = nil # The parent class responsible for sending emails
|
54
|
+
# config.deliver_method = nil # The deliver method, deliver_later or deliver_now
|
55
|
+
# config.mailer_layout = nil # Default mailer layout
|
56
|
+
# config.mailer_sender = nil # Default From value
|
57
|
+
# config.mailer_admin = nil # Default To value for Admin correspondence
|
58
|
+
# config.mailer_subject = nil # Proc.new method used to customize Subject
|
59
|
+
|
60
|
+
# Use effective email templates for event notifications
|
61
|
+
config.use_effective_email_templates = true
|
68
62
|
end
|
data/config/routes.rb
CHANGED
@@ -41,7 +41,7 @@ EffectiveCpd::Engine.routes.draw do
|
|
41
41
|
resources :cpd_audit_levels, except: [:show]
|
42
42
|
resources :cpd_audit_level_questions, except: [:show]
|
43
43
|
|
44
|
-
resources :cpd_audits, except: [:show
|
44
|
+
resources :cpd_audits, except: [:show]
|
45
45
|
resources :cpd_audit_reviews
|
46
46
|
end
|
47
47
|
|
@@ -75,14 +75,14 @@ class CreateEffectiveCpd < ActiveRecord::Migration[6.0]
|
|
75
75
|
t.references :cpd_category
|
76
76
|
t.references :original
|
77
77
|
|
78
|
-
t.
|
79
|
-
t.
|
78
|
+
t.decimal :amount, precision: 10, scale: 2
|
79
|
+
t.decimal :amount2, precision: 10, scale: 2
|
80
80
|
|
81
81
|
t.text :description
|
82
82
|
|
83
|
-
t.
|
84
|
-
t.
|
85
|
-
t.
|
83
|
+
t.decimal :carry_over, precision: 10, scale: 2
|
84
|
+
t.decimal :score, precision: 10, scale: 2
|
85
|
+
t.decimal :carry_forward, precision: 10, scale: 2
|
86
86
|
|
87
87
|
t.text :reduced_messages
|
88
88
|
|
@@ -98,7 +98,7 @@ class CreateEffectiveCpd < ActiveRecord::Migration[6.0]
|
|
98
98
|
|
99
99
|
t.string :token
|
100
100
|
|
101
|
-
t.
|
101
|
+
t.decimal :score, precision: 10, scale: 2
|
102
102
|
|
103
103
|
t.boolean :confirm_read
|
104
104
|
t.boolean :confirm_factual
|
data/lib/effective_cpd.rb
CHANGED
@@ -15,43 +15,14 @@ module EffectiveCpd
|
|
15
15
|
:cpd_audits_table_name, :cpd_audit_responses_table_name, :cpd_audit_response_options_table_name,
|
16
16
|
:cpd_audit_reviews_table_name, :cpd_audit_review_items_table_name,
|
17
17
|
:cycle_label, :credit_label, :layout, :auditee_user_scope, :audit_reviewer_user_scope,
|
18
|
-
:mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_admin, :use_effective_email_templates
|
18
|
+
:mailer, :parent_mailer, :deliver_method, :mailer_layout, :mailer_sender, :mailer_admin, :mailer_subject, :use_effective_email_templates
|
19
19
|
]
|
20
20
|
end
|
21
21
|
|
22
22
|
include EffectiveGem
|
23
23
|
|
24
24
|
def self.mailer_class
|
25
|
-
|
26
|
-
Effective::CpdMailer
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.parent_mailer_class
|
30
|
-
return parent_mailer.constantize if parent_mailer.present?
|
31
|
-
|
32
|
-
if use_effective_email_templates
|
33
|
-
require 'effective_email_templates'
|
34
|
-
Effective::EmailTemplatesMailer
|
35
|
-
else
|
36
|
-
ActionMailer::Base
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.send_email(email, *args)
|
41
|
-
raise('expected args to be an Array') unless args.kind_of?(Array)
|
42
|
-
|
43
|
-
if defined?(Tenant)
|
44
|
-
tenant = Tenant.current || raise('expected a current tenant')
|
45
|
-
args << { tenant: tenant }
|
46
|
-
end
|
47
|
-
|
48
|
-
deliver_method = EffectiveCpd.deliver_method || EffectiveResources.deliver_method
|
49
|
-
|
50
|
-
begin
|
51
|
-
EffectiveCpd.mailer_class.send(email, *args).send(deliver_method)
|
52
|
-
rescue => e
|
53
|
-
raise if Rails.env.development? || Rails.env.test?
|
54
|
-
end
|
25
|
+
mailer&.constantize || Effective::CpdMailer
|
55
26
|
end
|
56
27
|
|
57
28
|
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.
|
4
|
+
version: 0.3.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:
|
11
|
+
date: 2022-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -311,6 +311,7 @@ files:
|
|
311
311
|
- app/views/effective/cpd_audit_reviews/submit.html.haml
|
312
312
|
- app/views/effective/cpd_audit_reviews/waiting.html.haml
|
313
313
|
- app/views/effective/cpd_audits/_conflict.html.haml
|
314
|
+
- app/views/effective/cpd_audits/_cpd.html.haml
|
314
315
|
- app/views/effective/cpd_audits/_cpd_audit.html.haml
|
315
316
|
- app/views/effective/cpd_audits/_cpd_audit_level_section.html.haml
|
316
317
|
- app/views/effective/cpd_audits/_exemption.html.haml
|
@@ -321,6 +322,7 @@ files:
|
|
321
322
|
- app/views/effective/cpd_audits/_waiting.html.haml
|
322
323
|
- app/views/effective/cpd_audits/complete.html.haml
|
323
324
|
- app/views/effective/cpd_audits/conflict.html.haml
|
325
|
+
- app/views/effective/cpd_audits/cpd.html.haml
|
324
326
|
- app/views/effective/cpd_audits/cpd_audit_level_section.html.haml
|
325
327
|
- app/views/effective/cpd_audits/exemption.html.haml
|
326
328
|
- app/views/effective/cpd_audits/extension.html.haml
|
@@ -362,7 +364,6 @@ files:
|
|
362
364
|
- app/views/effective/cpd_statements/complete.html.haml
|
363
365
|
- app/views/effective/cpd_statements/start.html.haml
|
364
366
|
- app/views/effective/cpd_statements/submit.html.haml
|
365
|
-
- app/views/layouts/effective_cpd_mailer_layout.html.haml
|
366
367
|
- config/effective_cpd.rb
|
367
368
|
- config/routes.rb
|
368
369
|
- db/migrate/01_create_effective_cpd.rb.erb
|