effective_cpd 0.1.19 → 0.3.0

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.
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