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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/effective/cpd_audits_controller.rb +2 -0
  3. data/app/datatables/admin/effective_cpd_statements_datatable.rb +8 -2
  4. data/app/helpers/effective_cpd_helper.rb +5 -0
  5. data/app/mailers/effective/cpd_mailer.rb +139 -67
  6. data/app/models/concerns/effective_cpd_user.rb +4 -0
  7. data/app/models/effective/cpd_audit.rb +35 -20
  8. data/app/models/effective/cpd_audit_review.rb +1 -1
  9. data/app/models/effective/cpd_rule.rb +4 -2
  10. data/app/models/effective/cpd_scorer.rb +1 -1
  11. data/app/models/effective/cpd_statement.rb +4 -4
  12. data/app/models/effective/cpd_statement_activity.rb +6 -6
  13. data/app/views/effective/cpd_audits/_cpd.html.haml +13 -0
  14. data/app/views/effective/cpd_audits/_layout.html.haml +1 -1
  15. data/app/views/effective/cpd_audits/conflict.html.haml +2 -1
  16. data/app/views/effective/cpd_audits/cpd.html.haml +19 -0
  17. data/app/views/effective/cpd_audits/exemption.html.haml +2 -1
  18. data/app/views/effective/cpd_audits/extension.html.haml +2 -1
  19. data/app/views/effective/cpd_statement_activities/_cpd_statement_activity.html.haml +5 -5
  20. data/app/views/effective/cpd_statement_activities/_form.html.haml +5 -5
  21. data/app/views/effective/cpd_statements/_activities_new.html.haml +1 -1
  22. data/app/views/effective/cpd_statements/_activities_table.html.haml +6 -6
  23. data/app/views/effective/cpd_statements/_layout.html.haml +3 -3
  24. data/app/views/effective/cpd_statements/_summary.html.haml +2 -2
  25. data/config/effective_cpd.rb +16 -22
  26. data/config/routes.rb +1 -1
  27. data/db/migrate/01_create_effective_cpd.rb.erb +6 -6
  28. data/lib/effective_cpd/version.rb +1 -1
  29. data/lib/effective_cpd.rb +2 -31
  30. metadata +4 -3
  31. 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: fe768cdc3715d62c09b0c829d6823db4ce8587fd603244dceb4243976006bb02
4
- data.tar.gz: 0540bd3c67a6df4c5fbc2d612ccbc67f834ff46d96a605c2200ac8866f21dfbd
3
+ metadata.gz: 9940c548d939b8c1a285db0e19877bd4ed2147001fbebc947aaf6e02d548def6
4
+ data.tar.gz: 0547a9982f49587cbe07f2d3b65b6ab0da31be1728d7a55541cebd48cb560dde
5
5
  SHA512:
6
- metadata.gz: 00701f9319d26d59b192bf831d7072441661798a2202ba728cdf474b798fc9cfc5e3a013b5b725a45d58f6861192d48684acb6b3aec7508a7787d2e3608433c4
7
- data.tar.gz: a363248b7decc2a56fcc86d29748c3c29b97fe6ea256406a10f5a41af69064301158871851e8b3dbe2227e3bd40a8009e95a8f16601a4da8f629027d53e65470
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
- col :score
21
- col :carry_forward
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
@@ -44,4 +44,9 @@ module EffectiveCpdHelper
44
44
  @effective_cpd_categories ||= Effective::CpdCategory.deep.sorted
45
45
  end
46
46
 
47
+ def cpd_score(value)
48
+ raise('expected a BigDecimal') unless value.nil? || value.kind_of?(BigDecimal)
49
+ ("%.#{2}f" % value.to_d)
50
+ end
51
+
47
52
  end
@@ -1,122 +1,194 @@
1
1
  module Effective
2
2
  class CpdMailer < EffectiveCpd.parent_mailer_class
3
- default from: -> { EffectiveCpd.mailer_sender }
4
- layout -> { EffectiveCpd.mailer_layout || 'effective_cpd_mailer_layout' }
3
+
4
+ include EffectiveMailer
5
+ include EffectiveEmailTemplatesMailer if EffectiveCpd.use_effective_email_templates
5
6
 
6
7
  # CPD Audit
7
- def cpd_audit_opened(cpd_audit, opts = {})
8
- @assigns = effective_cpd_email_assigns(cpd_audit)
9
- @assigns.merge!(url: effective_cpd.cpd_audit_url(cpd_audit))
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: cpd_audit.user.email, **headers_for(cpd_audit, opts))
17
+ mail(to: resource.user.email, subject: subject, **headers)
12
18
  end
13
19
 
14
- def cpd_audit_conflicted(cpd_audit, opts = {})
15
- @assigns = effective_cpd_email_assigns(cpd_audit)
16
- @assigns.merge!(url: effective_cpd.edit_admin_cpd_audit_url(cpd_audit))
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: EffectiveCpd.mailer_admin, **headers_for(cpd_audit, opts))
29
+ mail(to: mailer_admin, subject: subject, **headers)
19
30
  end
20
31
 
21
- def cpd_audit_conflict_resolved(cpd_audit, opts = {})
22
- @assigns = effective_cpd_email_assigns(cpd_audit)
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
- mail(to: cpd_audit.user.email, **headers_for(cpd_audit, opts))
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(cpd_audit, opts = {})
29
- @assigns = effective_cpd_email_assigns(cpd_audit)
30
- @assigns.merge!(url: effective_cpd.edit_admin_cpd_audit_url(cpd_audit))
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: EffectiveCpd.mailer_admin, **headers_for(cpd_audit, opts))
53
+ mail(to: mailer_admin, subject: subject, **headers)
33
54
  end
34
55
 
35
- def cpd_audit_exemption_denied(cpd_audit, opts = {})
36
- @assigns = effective_cpd_email_assigns(cpd_audit)
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
- mail(to: cpd_audit.user.email, **headers_for(cpd_audit, opts))
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(cpd_audit, opts = {})
43
- @assigns = effective_cpd_email_assigns(cpd_audit)
44
- @assigns.merge!(url: effective_cpd.cpd_audit_url(cpd_audit))
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: cpd_audit.user.email, **headers_for(cpd_audit, opts))
77
+ mail(to: resource.user.email, subject: subject, **headers)
47
78
  end
48
79
 
49
- def cpd_audit_extension_request(cpd_audit, opts = {})
50
- @assigns = effective_cpd_email_assigns(cpd_audit)
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
- mail(to: EffectiveCpd.mailer_admin, **headers_for(cpd_audit, opts))
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(cpd_audit, opts = {})
57
- @assigns = effective_cpd_email_assigns(cpd_audit)
58
- @assigns.merge!(url: effective_cpd.cpd_audit_url(cpd_audit))
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: cpd_audit.user.email, **headers_for(cpd_audit, opts))
101
+ mail(to: resource.user.email, subject: subject, **headers)
61
102
  end
62
103
 
63
- def cpd_audit_extension_granted(cpd_audit, opts = {})
64
- @assigns = effective_cpd_email_assigns(cpd_audit)
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
- mail(to: cpd_audit.user.email, **headers_for(cpd_audit, opts))
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(cpd_audit, opts = {})
71
- @assigns = effective_cpd_email_assigns(cpd_audit)
72
- @assigns.merge!(url: effective_cpd.edit_admin_cpd_audit_url(cpd_audit))
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: EffectiveCpd.mailer_admin, **headers_for(cpd_audit, opts))
125
+ mail(to: mailer_admin, subject: subject, **headers)
75
126
  end
76
127
 
77
- def cpd_audit_reviewed(cpd_audit, opts = {})
78
- @assigns = effective_cpd_email_assigns(cpd_audit)
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
- mail(to: EffectiveCpd.mailer_admin, **headers_for(cpd_audit, opts))
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(cpd_audit, opts = {})
85
- @assigns = effective_cpd_email_assigns(cpd_audit)
86
- @assigns.merge!(url: effective_cpd.cpd_audit_url(cpd_audit))
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: cpd_audit.user.email, **headers_for(cpd_audit, opts))
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(cpd_audit_review, opts = {})
93
- @assigns = effective_cpd_email_assigns(cpd_audit_review)
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
- mail(to: cpd_audit_review.user.email, **headers_for(cpd_audit_review, opts))
97
- end
156
+ @assigns = assigns_for(resource).merge(url: effective_cpd.cpd_audit_review_url(resource))
157
+ @cpd_audit_review = resource
98
158
 
99
- def cpd_audit_review_ready(cpd_audit_review, opts = {})
100
- @assigns = effective_cpd_email_assigns(cpd_audit_review)
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: cpd_audit_review.user.email, **headers_for(cpd_audit_review, opts))
162
+ mail(to: resource.user.email, subject: subject, **headers)
104
163
  end
105
164
 
106
- def cpd_audit_review_submitted(cpd_audit_review, opts = {})
107
- @assigns = effective_cpd_email_assigns(cpd_audit_review)
108
- @assigns.merge!(url: effective_cpd.edit_admin_cpd_audit_url(cpd_audit_review.cpd_audit))
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
- mail(to: EffectiveCpd.mailer_admin, **headers_for(cpd_audit_review, opts))
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
- protected
177
+ def cpd_audit_review_submitted(resource, opts = {})
178
+ raise('expected an Effective::CpdAuditReview') unless resource.kind_of?(Effective::CpdAuditReview)
114
179
 
115
- def headers_for(resource, opts = {})
116
- resource.respond_to?(:log_changes_datatable) ? opts.merge(log: resource) : opts
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
- def effective_cpd_email_assigns(resource)
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
@@ -22,6 +22,10 @@ module EffectiveCpdUser
22
22
  nil
23
23
  end
24
24
 
25
+ def cpd_audit_cpd_required?
26
+ true
27
+ end
28
+
25
29
  module ClassMethods
26
30
  def effective_cpd_user?; true; end
27
31
  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
- eval(equation).round.to_i
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.to_i > 0
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.to_i, required_by_user.to_i].max
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.to_i }
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.to_i }
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 :integer
20
- amount2 :integer
19
+ amount :decimal
20
+ amount2 :decimal
21
21
 
22
22
  description :text
23
23
 
24
- carry_over :integer # carry_over_from_last_cycle
25
- score :integer
26
- carry_forward :integer # carry_forward_to_next_cycle
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.to_i > 0 }
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
@@ -17,7 +17,7 @@
17
17
 
18
18
  %tr
19
19
  %td
20
- %h4= last_3_scores.to_i
20
+ %h4= cpd_score(last_3_scores.to_d)
21
21
 
22
22
  %td #{cpd_credits_label} in last 3 #{cpd_cycles_label} (including this #{cpd_cycle_label})
23
23
 
@@ -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
- %p The deadline to declare a conflict of interest is: #{resource.deadline_to_conflict_of_interest.strftime('%F')}.
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
- %p The deadline to request an exemption is: #{resource.deadline_to_exemption.strftime('%F')}.
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
- %p The deadline to request an extension is: #{resource.deadline_to_extension.strftime('%F')}.
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.to_i
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.to_i
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.to_i
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.to_i
39
+ = cpd_score(f.object.carry_forward)
40
40
 
41
41
  .row
42
42
  .col
43
43
  - if activity.amount_label.present?
44
- = f.number_field :amount, label: activity.amount_label, required: true
44
+ = f.float_field :amount, label: activity.amount_label, required: true
45
45
 
46
46
  - if activity.amount2_label.present?
47
- = f.number_field :amount2, label: activity.amount2_label, required: true
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
@@ -12,7 +12,7 @@
12
12
  %h3
13
13
  #{category}
14
14
  %small
15
- = cpd_statement.score_per_category[category.id].to_i
15
+ = cpd_score(cpd_statement.score_per_category[category.id])
16
16
  - if rule.max_credits_per_cycle.present?
17
17
  = '/'
18
18
  = rule.max_credits_per_cycle
@@ -16,7 +16,7 @@
16
16
  %h3
17
17
  #{category}
18
18
  %small
19
- = cpd_statement.score_per_category[category.id].to_i
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.to_i
46
+ = cpd_score(statement_activity.score)
47
47
 
48
48
  .col-2.carry-forward
49
- = statement_activity.carry_forward.to_i
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.to_i
62
+ %h4= cpd_score(cpd_statement.score)
63
63
  .col-2.carry-forward
64
- %h4= cpd_statement.carry_forward.to_i
64
+ %h4= cpd_score(cpd_statement.carry_forward)
@@ -19,14 +19,14 @@
19
19
 
20
20
  %tr
21
21
  %td
22
- %h4= resource.score.to_i
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.to_i
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
 
@@ -24,8 +24,8 @@
24
24
 
25
25
  %tr
26
26
  %th Total #{cpd_credits_label.titleize}
27
- %td= cpd_statement.score
27
+ %td= cpd_score(cpd_statement.score)
28
28
 
29
29
  %tr
30
30
  %th Carry Forward
31
- %td= cpd_statement.carry_forward
31
+ %td= cpd_score(cpd_statement.carry_forward)
@@ -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 Configuration
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::CpdMailer'
48
-
49
- # Configure the parent class responsible to send e-mails.
50
- # config.parent_mailer = 'ActionMailer::Base'
51
-
52
- # Default deliver method
53
- # config.deliver_method = :deliver_later
54
-
55
- # Default layout
56
- config.mailer_layout = 'effective_cpd_mailer_layout'
57
-
58
- # Default From
59
- config.mailer_sender = "no-reply@example.com"
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, :destroy]
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.integer :amount
79
- t.integer :amount2
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.integer :carry_over
84
- t.integer :score
85
- t.integer :carry_forward
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.integer :score
101
+ t.decimal :score, precision: 10, scale: 2
102
102
 
103
103
  t.boolean :confirm_read
104
104
  t.boolean :confirm_factual
@@ -1,3 +1,3 @@
1
1
  module EffectiveCpd
2
- VERSION = '0.1.19'
2
+ VERSION = '0.3.0'
3
3
  end
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
- return mailer.constantize if mailer.present?
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.1.19
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: 2021-11-17 00:00:00.000000000 Z
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
@@ -1,7 +0,0 @@
1
- !!!
2
- %html{style: 'background: #fff;'}
3
- %head
4
- %meta{:content => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type'}
5
-
6
- %body{style: 'background: #fff;'}
7
- = yield