effective_cpd 0.1.2 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +17 -9
- data/app/assets/javascripts/effective_cpd/activities.js +6 -0
- data/app/controllers/admin/cpd_special_rules_controller.rb +13 -0
- data/app/datatables/admin/effective_cpd_special_rules_datatable.rb +23 -0
- data/app/helpers/effective_cpd_helper.rb +10 -0
- data/app/models/effective/cpd_cycle.rb +20 -2
- data/app/models/effective/cpd_rule.rb +24 -9
- data/app/models/effective/cpd_scorer.rb +23 -1
- data/app/models/effective/cpd_special_rule.rb +54 -0
- data/app/models/effective/cpd_special_rule_mate.rb +6 -0
- data/app/views/admin/cpd_cycles/_form.html.haml +3 -0
- data/app/views/admin/cpd_cycles/_form_content.html.haml +8 -0
- data/app/views/admin/cpd_cycles/_form_cpd_rules.html.haml +41 -33
- data/app/views/admin/cpd_cycles/_form_cpd_special_rules.html.haml +4 -0
- data/app/views/admin/cpd_special_rules/_form.html.haml +18 -0
- data/app/views/effective/cpd_statement_activities/_form.html.haml +1 -0
- data/app/views/effective/cpd_statements/_activities_new.html.haml +3 -0
- data/app/views/effective/cpd_statements/_activities_table.html.haml +1 -1
- data/app/views/effective/cpd_statements/_layout.html.haml +2 -0
- data/app/views/effective/cpd_statements/submit.html.haml +1 -2
- data/config/effective_cpd.rb +2 -0
- data/config/routes.rb +1 -0
- data/db/migrate/01_create_effective_cpd.rb.erb +18 -0
- data/db/seeds.rb +15 -13
- data/lib/effective_cpd.rb +1 -1
- data/lib/effective_cpd/version.rb +1 -1
- data/lib/generators/effective_cpd/install_generator.rb +2 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fa00b7ca9d6039709adb5c4948137632b28eeb8d8c551b5b489d9c4070722b51
|
4
|
+
data.tar.gz: b53448836a6adc80ad1430ad3c569b5ee4f19cb1bc10339dbc222b44998dd97c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9bbc1c8162e0c595d1c51ea8148caa59de3654993b5764a177a5c66eda39ed7f29554a2bb1cf2f31f3b1f2d8eeaf6373866e64bbbdcf00e3bf6f796b8e918ddb
|
7
|
+
data.tar.gz: 3f1cfa5651851f517a697f9cf540d3319b0f17583557d0e5dcf0d2a1e32c9de49a96b421c82b458677191650f7e722bd5468e133a610844f55a5474313324e12
|
data/README.md
CHANGED
@@ -144,18 +144,26 @@ You can also programatically do it. Add the following to your user class.
|
|
144
144
|
# This is an ActiveRecord concern to add the has_many :cpd_statements
|
145
145
|
effective_cpd_user
|
146
146
|
|
147
|
-
#
|
148
|
-
# Must be 100 points in the last 3 years. Can submit 0 0 100 or 33 33 34
|
147
|
+
# We require 100 points in the last 3 years.
|
149
148
|
def cpd_statement_required_score(cpd_statement)
|
150
|
-
#
|
151
|
-
|
152
|
-
|
149
|
+
# We always consider the 3 year window, of the passed cpd_statement and the last two statements
|
150
|
+
last_two_statements = cpd_statements.select do |statement|
|
151
|
+
statement.completed? && statement.cpd_cycle_id < cpd_statement.cpd_cycle_id
|
152
|
+
end.last(2)
|
153
153
|
|
154
|
-
|
155
|
-
|
156
|
-
return 0 if existing >= 100
|
154
|
+
# They can submit 0 0 100
|
155
|
+
return 0 if last_two_statements.length < 2
|
157
156
|
|
158
|
-
|
157
|
+
# 100 points in the last 3 years.
|
158
|
+
required_score = 100
|
159
|
+
|
160
|
+
# Score so far
|
161
|
+
existing_score = last_two_statements.sum { |statement| statement.score }
|
162
|
+
raise('expected existing_score to be >= 0') if existing_score < 0
|
163
|
+
|
164
|
+
# Required score minus previous
|
165
|
+
return 0 if existing_score >= required_score
|
166
|
+
(required_score - existing_score)
|
159
167
|
end
|
160
168
|
```
|
161
169
|
|
@@ -44,6 +44,12 @@ $(document).on('click', '[data-cpd-edit-activity]', function(event) {
|
|
44
44
|
$activity.children('.statement-activity-form').show()
|
45
45
|
});
|
46
46
|
|
47
|
+
// When we click any x button
|
48
|
+
$(document).on('click', '[data-cpd-collapse]', function(event) {
|
49
|
+
event.preventDefault()
|
50
|
+
collapse_effective_cpd_activities()
|
51
|
+
});
|
52
|
+
|
47
53
|
// Initializers
|
48
54
|
$(document).ready(function() { initialize_effective_cpd_activities() });
|
49
55
|
$(document).on('turbolinks:load', function() { initialize_effective_cpd_activities() });
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Admin
|
2
|
+
class CpdSpecialRulesController < ApplicationController
|
3
|
+
before_action(:authenticate_user!) if defined?(Devise)
|
4
|
+
before_action { EffectiveResources.authorize!(self, :admin, :effective_cpd) }
|
5
|
+
|
6
|
+
include Effective::CrudController
|
7
|
+
|
8
|
+
def permitted_params
|
9
|
+
params.require(:effective_cpd_special_rule).permit!
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Admin
|
2
|
+
class EffectiveCpdSpecialRulesDatatable < Effective::Datatable
|
3
|
+
datatable do
|
4
|
+
col :id, visible: false
|
5
|
+
col :created_at, visible: false
|
6
|
+
col :updated_at, visible: false
|
7
|
+
|
8
|
+
col :cpd_cycle, label: cpd_cycle_label.titleize
|
9
|
+
|
10
|
+
col :cpd_rules
|
11
|
+
|
12
|
+
col :category
|
13
|
+
col :max_credits_per_cycle, label: 'Max ' + cpd_credits_label.titleize
|
14
|
+
|
15
|
+
actions_col
|
16
|
+
end
|
17
|
+
|
18
|
+
collection do
|
19
|
+
cpd_cycle = Effective::CpdCycle.find(attributes[:cpd_cycle_id])
|
20
|
+
Effective::CpdSpecialRule.all.deep.where(cpd_cycle: cpd_cycle)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -30,6 +30,16 @@ module EffectiveCpdHelper
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
def cpd_statement_submit_label(cpd_statement)
|
34
|
+
label = "Yes, I understand I will not be able to submit more #{cpd_credits_label} or modify any of my activities for this #{cpd_cycle_label}, once I submit."
|
35
|
+
|
36
|
+
if (end_at = cpd_statement.cpd_cycle.end_at).present?
|
37
|
+
label += " The last date to submit this form is #{end_at.strftime("%B %d, %Y")}."
|
38
|
+
end
|
39
|
+
|
40
|
+
label
|
41
|
+
end
|
42
|
+
|
33
43
|
def effective_cpd_categories
|
34
44
|
@effective_cpd_categories ||= Effective::CpdCategory.deep.sorted
|
35
45
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Effective
|
2
2
|
class CpdCycle < ActiveRecord::Base
|
3
3
|
has_rich_text :all_steps_content # Update build_from_cycle() below if these change
|
4
|
+
has_rich_text :sidebar_content
|
4
5
|
has_rich_text :start_content
|
5
6
|
has_rich_text :activities_content
|
6
7
|
has_rich_text :agreements_content
|
@@ -10,6 +11,9 @@ module Effective
|
|
10
11
|
has_many :cpd_rules, dependent: :delete_all
|
11
12
|
accepts_nested_attributes_for :cpd_rules, allow_destroy: true
|
12
13
|
|
14
|
+
has_many :cpd_special_rules, dependent: :delete_all
|
15
|
+
accepts_nested_attributes_for :cpd_special_rules, allow_destroy: true
|
16
|
+
|
13
17
|
has_many :cpd_statements
|
14
18
|
|
15
19
|
if respond_to?(:log_changes)
|
@@ -29,6 +33,7 @@ module Effective
|
|
29
33
|
|
30
34
|
scope :deep, -> {
|
31
35
|
with_rich_text_all_steps_content
|
36
|
+
.with_rich_text_sidebar_content
|
32
37
|
.with_rich_text_start_content
|
33
38
|
.with_rich_text_activities_content
|
34
39
|
.with_rich_text_submit_content
|
@@ -76,13 +81,26 @@ module Effective
|
|
76
81
|
attributes = cycle.dup.attributes.except('title', 'token', 'start_at', 'end_at')
|
77
82
|
assign_attributes(attributes)
|
78
83
|
|
79
|
-
[:all_steps_content, :start_content, :activities_content, :submit_content, :complete_content].each do |rich_text|
|
84
|
+
[:all_steps_content, :sidebar_content, :start_content, :activities_content, :agreements_content, :submit_content, :complete_content].each do |rich_text|
|
80
85
|
self.send("#{rich_text}=", cycle.send(rich_text))
|
81
86
|
end
|
82
87
|
|
83
88
|
cycle.cpd_rules.each do |rule|
|
84
89
|
attributes = rule.dup.attributes.except('cpd_cycle_id')
|
85
|
-
self.cpd_rules.build(attributes)
|
90
|
+
cpd_rule = self.cpd_rules.build(attributes)
|
91
|
+
|
92
|
+
if rule.category?
|
93
|
+
cpd_rule.category_credit_description = rule.category_credit_description
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
cycle.cpd_special_rules.each do |special_rule|
|
98
|
+
attributes = special_rule.dup.attributes.except('cpd_cycle_id')
|
99
|
+
cpd_special_rule = self.cpd_special_rules.build(attributes)
|
100
|
+
|
101
|
+
special_rule.ruleables.each do |ruleable|
|
102
|
+
cpd_special_rule.cpd_special_rule_mates.build(cpd_rule: self.rule_for(ruleable))
|
103
|
+
end
|
86
104
|
end
|
87
105
|
|
88
106
|
self
|
@@ -3,16 +3,21 @@ module Effective
|
|
3
3
|
belongs_to :cpd_cycle
|
4
4
|
belongs_to :ruleable, polymorphic: true # Activity or Category
|
5
5
|
|
6
|
+
# For a Category: A maximum of 35 PDHs/year may be claimed in the Contributions to Knowledge category
|
7
|
+
has_rich_text :category_credit_description
|
8
|
+
|
9
|
+
has_many :cpd_special_rule_mates, dependent: :destroy, inverse_of: :cpd_rule
|
10
|
+
has_many :cpd_special_rules, -> { CpdSpecialRule.sorted }, through: :cpd_special_rule_mates
|
11
|
+
|
6
12
|
if respond_to?(:log_changes)
|
7
13
|
log_changes(to: :cpd_cycle)
|
8
14
|
end
|
9
15
|
|
10
|
-
# Only permit the words amount, amount2 and any charater 0-9 + - / * ( )
|
11
|
-
INVALID_FORMULA_CHARS = /[^0-9
|
16
|
+
# Only permit the words amount, amount2 and any charater 0-9 + - / * . ( )
|
17
|
+
INVALID_FORMULA_CHARS = /[^0-9\+\-\.\/\*\(\)]/
|
12
18
|
|
13
19
|
effective_resource do
|
14
20
|
# A plaintext description of the formula
|
15
|
-
# For a Category: A maximum of 35 PDHs/year may be claimed in the Contributions to Knowledge category
|
16
21
|
# For a Activity: 15 hours of work equals 1 credit
|
17
22
|
credit_description :text
|
18
23
|
|
@@ -23,6 +28,7 @@ module Effective
|
|
23
28
|
formula :string
|
24
29
|
|
25
30
|
# Maximum number of cycles can carry forward
|
31
|
+
# Only considered for activities
|
26
32
|
max_cycles_can_carry_forward :integer
|
27
33
|
|
28
34
|
# Cannot be entered in this cycle
|
@@ -31,22 +37,25 @@ module Effective
|
|
31
37
|
timestamps
|
32
38
|
end
|
33
39
|
|
34
|
-
scope :
|
40
|
+
scope :sorted, -> { order(:id) }
|
41
|
+
scope :deep, -> { with_rich_text_category_credit_description.includes(:cpd_cycle, :ruleable) }
|
35
42
|
scope :categories, -> { where(ruleable_type: 'Effective::CpdCategory') }
|
36
43
|
scope :activities, -> { where(ruleable_type: 'Effective::CpdActivity') }
|
37
44
|
scope :unavailable, -> { where(unavailable: true) }
|
38
45
|
|
39
46
|
#validates :cpd_cycle_id, uniqueness: { scope: [:ruleable_id, :ruleable_type] }
|
40
|
-
validates :credit_description, presence: true
|
41
47
|
validates :max_credits_per_cycle, numericality: { greater_than: 0, allow_nil: true }
|
42
|
-
validates :max_cycles_can_carry_forward, numericality: {
|
48
|
+
validates :max_cycles_can_carry_forward, numericality: { greater_than_or_equal_to: 0, allow_nil: true }
|
43
49
|
|
44
50
|
validates :formula, presence: true, if: -> { activity? }
|
45
51
|
validates :formula, absence: true, if: -> { category? }
|
46
52
|
|
53
|
+
validates :credit_description, presence: true, if: -> { activity? }
|
54
|
+
validates :category_credit_description, presence: true, if: -> { category? }
|
55
|
+
|
47
56
|
validate(if: -> { formula.present? }) do
|
48
57
|
if formula.gsub('amount2', '').gsub('amount', '').gsub(' ', '').match(INVALID_FORMULA_CHARS).present?
|
49
|
-
self.errors.add(:formula, "may only contain amount, amount2 and 0-9 + - / * ( ) characters")
|
58
|
+
self.errors.add(:formula, "may only contain amount, amount2 and 0-9 + - / * . ( ) characters")
|
50
59
|
else
|
51
60
|
begin
|
52
61
|
eval_equation(amount: 0, amount2: 0)
|
@@ -79,7 +88,13 @@ module Effective
|
|
79
88
|
end
|
80
89
|
|
81
90
|
def to_s
|
82
|
-
|
91
|
+
if activity?
|
92
|
+
formula.presence || ruleable.to_s.presence || 'activity rule'
|
93
|
+
elsif category?
|
94
|
+
ruleable.to_s.presence || 'category rule'
|
95
|
+
else
|
96
|
+
'new rule'
|
97
|
+
end
|
83
98
|
end
|
84
99
|
|
85
100
|
def activity?
|
@@ -103,7 +118,7 @@ module Effective
|
|
103
118
|
|
104
119
|
def eval_equation(amount: nil, amount2: nil)
|
105
120
|
equation = formula.gsub('amount2', amount2.to_s).gsub('amount', amount.to_s)
|
106
|
-
eval(equation).to_i
|
121
|
+
eval(equation).round.to_i
|
107
122
|
end
|
108
123
|
|
109
124
|
end
|
@@ -78,7 +78,7 @@ module Effective
|
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
|
-
# This
|
81
|
+
# This enforces CycleCategory.max_credits_per_cycle
|
82
82
|
statement.cpd_statement_activities.group_by(&:cpd_category).each do |cpd_category, activities|
|
83
83
|
rule = cycle.rule_for(cpd_category)
|
84
84
|
max_credits_per_cycle = rule.max_credits_per_cycle
|
@@ -98,6 +98,28 @@ module Effective
|
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
+
# This enforces cumulative max credits CpdSpecialRule.max_credits_per_cycle special rules
|
102
|
+
cycle.cpd_special_rules.select(&:cumulative_max_credits?).each do |special_rule|
|
103
|
+
cpd_categories = special_rule.ruleables.select { |obj| obj.kind_of?(Effective::CpdCategory) }
|
104
|
+
|
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
|
107
|
+
|
108
|
+
activities = statement.cpd_statement_activities.select { |sa| cpd_categories.include?(sa.cpd_category) }
|
109
|
+
|
110
|
+
activities.each do |activity|
|
111
|
+
next if activity.marked_for_destruction?
|
112
|
+
|
113
|
+
max_credits_per_cycle -= activity.score # We're already scored. Counting down...
|
114
|
+
|
115
|
+
if max_credits_per_cycle < 0
|
116
|
+
activity.score = [activity.score + max_credits_per_cycle, 0].max
|
117
|
+
activity.carry_forward = activity.max_score - activity.score
|
118
|
+
activity.reduced_messages["category_#{activity.cpd_category_id}"] = "You have reached the cumulative maximum of #{special_rule.max_credits_per_cycle}/#{cpd_cycle_label} for activities in the #{cpd_categories.map(&:to_s).to_sentence} categories"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
101
123
|
# This enforces the max_cycles_can_carry_forward logic
|
102
124
|
# If an Activity cannot be carried forward another cycle, its carry_forward should be 0
|
103
125
|
next_cycle = @cycles[@cycles.index(cycle) + 1]
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Effective
|
2
|
+
class CpdSpecialRule < ActiveRecord::Base
|
3
|
+
belongs_to :cpd_cycle
|
4
|
+
|
5
|
+
has_many :cpd_special_rule_mates, dependent: :destroy, inverse_of: :cpd_special_rule
|
6
|
+
has_many :cpd_rules, -> { CpdRule.sorted }, through: :cpd_special_rule_mates
|
7
|
+
|
8
|
+
if respond_to?(:log_changes)
|
9
|
+
log_changes
|
10
|
+
end
|
11
|
+
|
12
|
+
CATEGORIES = ['cumulative max credits']
|
13
|
+
|
14
|
+
effective_resource do
|
15
|
+
category :string # Special rule tyoes
|
16
|
+
|
17
|
+
# For cumulative max credits
|
18
|
+
max_credits_per_cycle :integer
|
19
|
+
|
20
|
+
timestamps
|
21
|
+
end
|
22
|
+
|
23
|
+
scope :deep, -> { includes(:cpd_special_rule_mates, cpd_rules: [:ruleable]) }
|
24
|
+
scope :sorted, -> { order(:id) }
|
25
|
+
|
26
|
+
before_validation do
|
27
|
+
self.category ||= CATEGORIES.first
|
28
|
+
end
|
29
|
+
|
30
|
+
validates :category, presence: true, inclusion: { in: CATEGORIES }
|
31
|
+
|
32
|
+
with_options(if: -> { cumulative_max_credits? }) do
|
33
|
+
validates :max_credits_per_cycle, presence: true, numericality: { greater_than: 0 }
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_s
|
37
|
+
if cumulative_max_credits?
|
38
|
+
"Cumulative max #{max_credits_per_cycle} credits"
|
39
|
+
else
|
40
|
+
'cpd special rule'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def cumulative_max_credits?
|
45
|
+
category == 'cumulative max credits'
|
46
|
+
end
|
47
|
+
|
48
|
+
# Right now this is going to be just Effective::CpdCategory objects
|
49
|
+
def ruleables
|
50
|
+
cpd_rules.map(&:ruleable)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -3,6 +3,9 @@
|
|
3
3
|
= render 'admin/cpd_cycles/form_cpd_cycle', cpd_cycle: cpd_cycle
|
4
4
|
|
5
5
|
- if cpd_cycle.persisted?
|
6
|
+
= tab 'Special Rules' do
|
7
|
+
= render 'admin/cpd_cycles/form_cpd_special_rules', cpd_cycle: cpd_cycle
|
8
|
+
|
6
9
|
= tab 'Category and Activity Rules' do
|
7
10
|
= tabs do
|
8
11
|
- Effective::CpdCategory.deep.sorted.each do |cpd_category|
|
@@ -1,9 +1,17 @@
|
|
1
1
|
= effective_form_with(model: [:admin, cpd_cycle], engine: true) do |f|
|
2
|
+
%h2 All Steps Content
|
3
|
+
|
2
4
|
.card.mb-4
|
3
5
|
.card-body
|
4
6
|
%h5.card-title All Steps Content
|
5
7
|
= f.rich_text_area :all_steps_content, label: false, hint: 'displayed on all statement steps'
|
6
8
|
|
9
|
+
.card.mb-4
|
10
|
+
.card-body
|
11
|
+
%h5.card-title Sidebar Content
|
12
|
+
= f.rich_text_area :sidebar_content, label: false, hint: 'displayed on the sidebar on all statement steps'
|
13
|
+
|
14
|
+
%h2 Individual Steps Content
|
7
15
|
.card.mb-4
|
8
16
|
.card-body
|
9
17
|
%h5.card-title Start Step
|
@@ -1,4 +1,5 @@
|
|
1
1
|
- edit_path = effective_cpd.edit_admin_cpd_category_path(cpd_category)
|
2
|
+
- cpd_rule = cpd_cycle.rule_for(cpd_category)
|
2
3
|
|
3
4
|
= effective_form_with(model: [:admin, cpd_cycle], engine: true) do |f|
|
4
5
|
%h2= cpd_category
|
@@ -6,51 +7,58 @@
|
|
6
7
|
%p= link_to 'Edit Category', edit_path, target: '_blank'
|
7
8
|
|
8
9
|
= f.fields_for :cpd_rules, cpd_cycle.rule_for(cpd_category) do |fc|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
.row
|
11
|
+
.col
|
12
|
+
= fc.number_field :max_credits_per_cycle,
|
13
|
+
label: "Max #{cpd_credits_label} per #{cpd_cycle_label}",
|
14
|
+
hint: "The maximum number of #{cpd_credits_label} that may be earned in this category for this #{cpd_cycle_label}. Leave blank for no limit."
|
15
|
+
.col
|
16
|
+
= fc.select :cpd_special_rule_ids, cpd_cycle.cpd_special_rules, multiple: true,
|
17
|
+
label: 'Special Rules', hint: "Special rules operate on more than one category at a time"
|
18
|
+
|
19
|
+
= fc.rich_text_area :category_credit_description,
|
20
|
+
hint: "A description of the maximum #{cpd_credits_label} and carry forward policy of activities for this category"
|
15
21
|
|
16
22
|
= fc.check_box :unavailable, label: "Unavailable in this #{cpd_cycle_label}"
|
17
23
|
|
18
24
|
= f.submit
|
19
25
|
|
20
|
-
|
21
|
-
%h2 Activities
|
22
|
-
- rules = cpd_category.cpd_activities.map { |activity| cpd_cycle.rule_for(activity) }
|
26
|
+
- unless cpd_rule.unavailable?
|
23
27
|
|
24
|
-
=
|
25
|
-
|
28
|
+
= effective_form_with(model: [:admin, cpd_cycle], engine: true) do |f|
|
29
|
+
%h2 Activities
|
30
|
+
- rules = cpd_category.cpd_activities.map { |activity| cpd_cycle.rule_for(activity) }
|
26
31
|
|
27
|
-
=
|
28
|
-
.
|
29
|
-
.col
|
30
|
-
%h5.card-title= activity
|
31
|
-
- if activity.body.present?
|
32
|
-
%p= activity.body
|
32
|
+
= f.fields_for :cpd_rules, rules do |fa|
|
33
|
+
- activity = fa.object.ruleable
|
33
34
|
|
34
|
-
|
35
|
+
= card do
|
36
|
+
.row
|
37
|
+
.col
|
38
|
+
%h5.card-title= activity
|
39
|
+
- if activity.body.present?
|
40
|
+
%p= activity.body
|
35
41
|
|
36
|
-
|
37
|
-
= f.static_field :amount2_label, value: activity.amount2_label.presence || '-'
|
38
|
-
= f.static_field :requires_upload_file, value: (activity.requires_upload_file ? 'Yes' : '-')
|
42
|
+
%p= link_to 'Edit Activity', edit_path, target: '_blank'
|
39
43
|
|
40
|
-
|
41
|
-
|
44
|
+
= f.static_field :amount_label, value: activity.amount_label.presence || '-'
|
45
|
+
= f.static_field :amount2_label, value: activity.amount2_label.presence || '-'
|
46
|
+
= f.static_field :requires_upload_file, value: (activity.requires_upload_file ? 'Yes' : '-')
|
42
47
|
|
43
|
-
|
44
|
-
|
48
|
+
.col
|
49
|
+
= fa.text_field :formula, hint: cpd_rule_formula_hint(activity)
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
hint: 'leave blank for no limit'
|
51
|
+
= fa.text_field :credit_description, label: "#{cpd_credits_label.titleize} description",
|
52
|
+
hint: "A simple description of the formula and its #{cpd_credits_label} calculation"
|
49
53
|
|
50
|
-
|
51
|
-
|
52
|
-
|
54
|
+
= fa.number_field :max_credits_per_cycle,
|
55
|
+
label: "Max #{cpd_credits_label} per #{cpd_cycle_label}",
|
56
|
+
hint: 'leave blank for no limit'
|
53
57
|
|
54
|
-
|
58
|
+
= fa.number_field :max_cycles_can_carry_forward,
|
59
|
+
label: "Max #{cpd_cycles_label} can carry forward",
|
60
|
+
hint: "leave blank for no limit. enter zero for no carry forward."
|
55
61
|
|
56
|
-
|
62
|
+
= fa.check_box :unavailable, label: "Unavailable in this #{cpd_cycle_label}"
|
63
|
+
|
64
|
+
= f.submit
|
@@ -0,0 +1,18 @@
|
|
1
|
+
= effective_form_with(model: [:admin, cpd_special_rule], engine: true) do |f|
|
2
|
+
- if inline_datatable?
|
3
|
+
= f.hidden_field :cpd_cycle_id
|
4
|
+
- else
|
5
|
+
= f.select :cpd_cycle_id, Effective::CpdCycle.sorted.all, label: cpd_cycle_label.titleize
|
6
|
+
|
7
|
+
= f.select :category, Effective::CpdSpecialRule::CATEGORIES
|
8
|
+
|
9
|
+
= f.show_if :category, 'cumulative max credits' do
|
10
|
+
= f.number_field :max_credits_per_cycle, label: "Cumulative max credits per #{cpd_cycle_label}",
|
11
|
+
hint: "The cumulative max #{cpd_credits_label} per #{cpd_cycle_label} that can be earned between the following categories."
|
12
|
+
|
13
|
+
- cpd_category_rules = cpd_special_rule.cpd_cycle.cpd_rules.select(&:category?)
|
14
|
+
|
15
|
+
= f.select :cpd_rule_ids, cpd_category_rules, label: 'Cumulative max included categories',
|
16
|
+
hint: "These categories will shared a maximum cumulative #{cpd_credits_label} per #{cpd_cycle_label}."
|
17
|
+
|
18
|
+
= effective_submit(f)
|
@@ -7,6 +7,8 @@
|
|
7
7
|
- next if rule.unavailable?
|
8
8
|
|
9
9
|
= tab(category) do
|
10
|
+
.float-right= link_to icon('x', class: 'small-1'), '#', 'data-cpd-collapse': true
|
11
|
+
|
10
12
|
%h3
|
11
13
|
#{category}
|
12
14
|
%small
|
@@ -22,6 +24,7 @@
|
|
22
24
|
.mb-3
|
23
25
|
%strong #{cpd_credits_label.titleize} Calculation
|
24
26
|
%br
|
27
|
+
= rule.category_credit_description
|
25
28
|
= rule.credit_description
|
26
29
|
|
27
30
|
%div
|
@@ -14,7 +14,6 @@
|
|
14
14
|
= effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
|
15
15
|
= f.hidden_field :current_step
|
16
16
|
|
17
|
-
= f.check_box :confirm_readonly,
|
18
|
-
label: 'Yes, I understand that I will not be able to modify this statement after submission'
|
17
|
+
= f.check_box :confirm_readonly, label: cpd_statement_submit_label(f.object)
|
19
18
|
|
20
19
|
= f.submit 'Submit Statement', center: true
|
data/config/effective_cpd.rb
CHANGED
@@ -4,6 +4,8 @@ EffectiveCpd.setup do |config|
|
|
4
4
|
|
5
5
|
config.cpd_cycles_table_name = :cpd_cycles
|
6
6
|
config.cpd_rules_table_name = :cpd_rules
|
7
|
+
config.cpd_special_rules_table_name = :cpd_special_rules
|
8
|
+
config.cpd_special_rule_mates_table_name = :cpd_special_rule_mates
|
7
9
|
|
8
10
|
config.cpd_statements_table_name = :cpd_statements
|
9
11
|
config.cpd_statement_activities_table_name = :cpd_statement_activities
|
data/config/routes.rb
CHANGED
@@ -32,6 +32,7 @@ EffectiveCpd::Engine.routes.draw do
|
|
32
32
|
resources :cpd_activities, except: [:show]
|
33
33
|
resources :cpd_cycles, except: [:show]
|
34
34
|
resources :cpd_rules, only: [:index]
|
35
|
+
resources :cpd_special_rules, except: [:show]
|
35
36
|
|
36
37
|
resources :cpd_statements, only: [:index, :show]
|
37
38
|
|
@@ -51,6 +51,24 @@ class CreateEffectiveCpd < ActiveRecord::Migration[6.0]
|
|
51
51
|
t.datetime :created_at
|
52
52
|
end
|
53
53
|
|
54
|
+
create_table <%= @cpd_special_rules_table_name %> do |t|
|
55
|
+
t.references :cpd_cycle
|
56
|
+
|
57
|
+
t.integer :max_credits_per_cycle
|
58
|
+
t.string :category
|
59
|
+
|
60
|
+
t.datetime :updated_at
|
61
|
+
t.datetime :created_at
|
62
|
+
end
|
63
|
+
|
64
|
+
create_table <%= @cpd_special_rule_mates_table_name %> do |t|
|
65
|
+
t.references :cpd_rule
|
66
|
+
t.references :cpd_special_rule
|
67
|
+
|
68
|
+
t.datetime :updated_at
|
69
|
+
t.datetime :created_at
|
70
|
+
end
|
71
|
+
|
54
72
|
create_table <%= @cpd_statement_activities_table_name %> do |t|
|
55
73
|
t.references :cpd_statement
|
56
74
|
t.references :cpd_activity
|
data/db/seeds.rb
CHANGED
@@ -7,9 +7,10 @@ if Rails.env.test?
|
|
7
7
|
Effective::CpdCategory.delete_all
|
8
8
|
Effective::CpdActivity.delete_all
|
9
9
|
Effective::CpdRule.delete_all
|
10
|
+
Effective::CpdSpecialRule.delete_all
|
11
|
+
Effective::CpdSpecialRuleMate.delete_all
|
10
12
|
|
11
13
|
ActionText::RichText.where(record_type: ['Effective::CpdCycle', 'Effective::CpdCycle', 'Effective::CpdActivity', 'Effective::CpdAudit', 'Effective::CpdAuditLevelSection', 'Effective::CpdAuditLevelQuestion']).delete_all
|
12
|
-
|
13
14
|
end
|
14
15
|
|
15
16
|
# Build the first CpdCycle
|
@@ -18,11 +19,12 @@ cycle = Effective::CpdCycle.create!(
|
|
18
19
|
start_at: now.beginning_of_year,
|
19
20
|
end_at: now.end_of_year,
|
20
21
|
required_score: 100,
|
21
|
-
all_steps_content: "
|
22
|
-
start_content: "
|
23
|
-
activities_content: "
|
24
|
-
submit_content: "
|
25
|
-
complete_content: "
|
22
|
+
all_steps_content: "All Steps Content",
|
23
|
+
start_content: "Start Content",
|
24
|
+
activities_content: "Activities Content",
|
25
|
+
submit_content: "Submit Content",
|
26
|
+
complete_content: "Complete Content",
|
27
|
+
sidebar_content: "Sidebar Content"
|
26
28
|
)
|
27
29
|
|
28
30
|
# Professional Practice
|
@@ -33,7 +35,7 @@ category = Effective::CpdCategory.create!(
|
|
33
35
|
Effective::CpdRule.create!(
|
34
36
|
cpd_cycle: cycle,
|
35
37
|
ruleable: category,
|
36
|
-
|
38
|
+
category_credit_description: 'Upto a maximum of 20 claimable points per CPD year. Points cannot be carried forward to future years.',
|
37
39
|
max_credits_per_cycle: 20
|
38
40
|
)
|
39
41
|
|
@@ -74,7 +76,7 @@ category = Effective::CpdCategory.create!(
|
|
74
76
|
Effective::CpdRule.create!(
|
75
77
|
cpd_cycle: cycle,
|
76
78
|
ruleable: category,
|
77
|
-
|
79
|
+
category_credit_description: 'Upto a maximum of 20 claimable points per CPD year. Points cannot be carried forward to future years.',
|
78
80
|
max_credits_per_cycle: 20
|
79
81
|
)
|
80
82
|
|
@@ -144,7 +146,7 @@ category = Effective::CpdCategory.create!(
|
|
144
146
|
Effective::CpdRule.create!(
|
145
147
|
cpd_cycle: cycle,
|
146
148
|
ruleable: category,
|
147
|
-
|
149
|
+
category_credit_description: 'Upto a maximum of 35 claimable points per CPD year. Points may be carried over upto a maximum of 2 years after the year in which they were earned.',
|
148
150
|
max_credits_per_cycle: 35
|
149
151
|
)
|
150
152
|
|
@@ -183,7 +185,7 @@ category = Effective::CpdCategory.create!(
|
|
183
185
|
Effective::CpdRule.create!(
|
184
186
|
cpd_cycle: cycle,
|
185
187
|
ruleable: category,
|
186
|
-
|
188
|
+
category_credit_description: 'Upto a maximum of 15 claimable points per CPD year. Points may be carried over upto a maximum of 2 years after the year in which they were earned.',
|
187
189
|
max_credits_per_cycle: 15
|
188
190
|
)
|
189
191
|
|
@@ -265,7 +267,7 @@ category = Effective::CpdCategory.create!(
|
|
265
267
|
Effective::CpdRule.create!(
|
266
268
|
cpd_cycle: cycle,
|
267
269
|
ruleable: category,
|
268
|
-
|
270
|
+
category_credit_description: 'Upto a maximum of 15 claimable points per CPD year. Points may be carried over upto a maximum of 2 years after the year in which they were earned.',
|
269
271
|
max_credits_per_cycle: 15
|
270
272
|
)
|
271
273
|
|
@@ -319,7 +321,7 @@ category = Effective::CpdCategory.create!(
|
|
319
321
|
Effective::CpdRule.create!(
|
320
322
|
cpd_cycle: cycle,
|
321
323
|
ruleable: category,
|
322
|
-
|
324
|
+
category_credit_description: 'Upto a maximum of 30 claimable points per CPD year. Points may be carried over upto a maximum of 2 years after the year in which they were earned.',
|
323
325
|
max_credits_per_cycle: 30
|
324
326
|
)
|
325
327
|
|
@@ -421,7 +423,7 @@ category = Effective::CpdCategory.create!(
|
|
421
423
|
Effective::CpdRule.create!(
|
422
424
|
cpd_cycle: cycle,
|
423
425
|
ruleable: category,
|
424
|
-
|
426
|
+
category_credit_description: 'Upto a maximum of 10 points per mentee or position per CPD year. Points may be carried over upto a maximum of 2 years after the year in which they were earned.',
|
425
427
|
max_credits_per_cycle: nil
|
426
428
|
)
|
427
429
|
|
data/lib/effective_cpd.rb
CHANGED
@@ -8,7 +8,7 @@ module EffectiveCpd
|
|
8
8
|
def self.config_keys
|
9
9
|
[
|
10
10
|
:cpd_categories_table_name, :cpd_activities_table_name,
|
11
|
-
:cpd_cycles_table_name, :cpd_rules_table_name,
|
11
|
+
:cpd_cycles_table_name, :cpd_rules_table_name, :cpd_special_rules_table_name, :cpd_special_rule_mates_table_name,
|
12
12
|
:cpd_statements_table_name, :cpd_statement_activities_table_name,
|
13
13
|
:cpd_audit_levels_table_name, :cpd_audit_level_sections_table_name,
|
14
14
|
:cpd_audit_level_questions_table_name, :cpd_audit_level_question_options_table_name,
|
@@ -25,6 +25,8 @@ module EffectiveCpd
|
|
25
25
|
|
26
26
|
@cpd_cycles_table_name = ':' + EffectiveCpd.cpd_cycles_table_name.to_s
|
27
27
|
@cpd_rules_table_name = ':' + EffectiveCpd.cpd_rules_table_name.to_s
|
28
|
+
@cpd_special_rules_table_name = ':' + EffectiveCpd.cpd_special_rules_table_name.to_s
|
29
|
+
@cpd_special_rule_mates_table_name = ':' + EffectiveCpd.cpd_special_rule_mates_table_name.to_s
|
28
30
|
|
29
31
|
@cpd_statements_table_name = ':' + EffectiveCpd.cpd_statements_table_name.to_s
|
30
32
|
@cpd_statement_activities_table_name = ':' + EffectiveCpd.cpd_statement_activities_table_name.to_s
|
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.
|
4
|
+
version: 0.1.7
|
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-05-
|
11
|
+
date: 2021-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -188,6 +188,7 @@ files:
|
|
188
188
|
- app/controllers/admin/cpd_categories_controller.rb
|
189
189
|
- app/controllers/admin/cpd_cycles_controller.rb
|
190
190
|
- app/controllers/admin/cpd_rules_controller.rb
|
191
|
+
- app/controllers/admin/cpd_special_rules_controller.rb
|
191
192
|
- app/controllers/admin/cpd_statements_controller.rb
|
192
193
|
- app/controllers/effective/cpd_audit_reviews_controller.rb
|
193
194
|
- app/controllers/effective/cpd_audits_controller.rb
|
@@ -202,6 +203,7 @@ files:
|
|
202
203
|
- app/datatables/admin/effective_cpd_categories_datatable.rb
|
203
204
|
- app/datatables/admin/effective_cpd_cycles_datatable.rb
|
204
205
|
- app/datatables/admin/effective_cpd_rules_datatable.rb
|
206
|
+
- app/datatables/admin/effective_cpd_special_rules_datatable.rb
|
205
207
|
- app/datatables/admin/effective_cpd_statements_datatable.rb
|
206
208
|
- app/datatables/effective_cpd_available_audit_reviews_datatable.rb
|
207
209
|
- app/datatables/effective_cpd_available_audits_datatable.rb
|
@@ -227,6 +229,8 @@ files:
|
|
227
229
|
- app/models/effective/cpd_cycle.rb
|
228
230
|
- app/models/effective/cpd_rule.rb
|
229
231
|
- app/models/effective/cpd_scorer.rb
|
232
|
+
- app/models/effective/cpd_special_rule.rb
|
233
|
+
- app/models/effective/cpd_special_rule_mate.rb
|
230
234
|
- app/models/effective/cpd_statement.rb
|
231
235
|
- app/models/effective/cpd_statement_activity.rb
|
232
236
|
- app/views/admin/cpd_activities/_form.html.haml
|
@@ -253,6 +257,8 @@ files:
|
|
253
257
|
- app/views/admin/cpd_cycles/_form_content.html.haml
|
254
258
|
- app/views/admin/cpd_cycles/_form_cpd_cycle.html.haml
|
255
259
|
- app/views/admin/cpd_cycles/_form_cpd_rules.html.haml
|
260
|
+
- app/views/admin/cpd_cycles/_form_cpd_special_rules.html.haml
|
261
|
+
- app/views/admin/cpd_special_rules/_form.html.haml
|
256
262
|
- app/views/admin/cpd_statements/_cpd_statement.html.haml
|
257
263
|
- app/views/effective/cpd_audit_level_questions/_cpd_audit_level_question.html.haml
|
258
264
|
- app/views/effective/cpd_audit_responses/_cpd_audit_response.html.haml
|