effective_memberships 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/admin/membership_histories_controller.rb +24 -0
- data/app/controllers/admin/memberships_controller.rb +15 -0
- data/app/controllers/admin/organizations_controller.rb +1 -1
- data/app/datatables/admin/effective_applicant_references_datatable.rb +22 -20
- data/app/datatables/admin/effective_fees_datatable.rb +2 -2
- data/app/datatables/admin/effective_membership_histories_datatable.rb +7 -3
- data/app/datatables/admin/effective_memberships_datatable.rb +2 -2
- data/app/models/concerns/effective_memberships_owner.rb +44 -0
- data/app/models/effective/membership.rb +24 -2
- data/app/models/effective/membership_history.rb +15 -0
- data/app/views/admin/membership_histories/_form.html.haml +19 -0
- data/app/views/admin/membership_histories/_validation.html.haml +7 -0
- data/app/views/admin/memberships/_form.html.haml +17 -0
- data/app/views/admin/memberships/_form_membership.html.haml +22 -0
- data/config/routes.rb +2 -1
- data/lib/effective_memberships/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 885423c81ffcee648c3ad06826b943ed31f9ed059432e9eda6a55b24a0f07ec0
|
4
|
+
data.tar.gz: 3b7c8ed91242b0cd0648cdca9f5e9b70af40bc5f7be7fb3ad585dfbe147c7909
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57654df20abfb3444de50023ea70cc011a28254ac8e986b54b158dc171fffb5c49c4b560128fe6d9ca937fb5f143031c4d4e3eaa372a12cede3968e476de1dfe
|
7
|
+
data.tar.gz: b15c8258ebfbeb653bf4cf5745ef0f63ded375c4326ed32ac5050f6adb7a4d92d6c79d35e914b288d1dbad70f0547e912379783224ef0b737bb6923f334c6029
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Admin
|
2
|
+
class MembershipHistoriesController < ApplicationController
|
3
|
+
before_action(:authenticate_user!) if defined?(Devise)
|
4
|
+
before_action { EffectiveResources.authorize!(self, :admin, :effective_memberships) }
|
5
|
+
|
6
|
+
include Effective::CrudController
|
7
|
+
|
8
|
+
submit :save, 'Update History',
|
9
|
+
success: -> { "Membership history successfully updated. Please double check the history is correct." },
|
10
|
+
redirect: -> { admin_owners_path(resource) }
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def permitted_params
|
15
|
+
model = (params.key?(:effective_membership_history) ? :effective_membership_history : :membership_history)
|
16
|
+
params.require(model).permit!
|
17
|
+
end
|
18
|
+
|
19
|
+
def admin_owners_path(resource)
|
20
|
+
Effective::Resource.new(resource.owner, namespace: :admin).action_path(:edit) + '?tab=membership'
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -5,5 +5,20 @@ module Admin
|
|
5
5
|
|
6
6
|
include Effective::CrudController
|
7
7
|
|
8
|
+
submit :save, 'Update Membership',
|
9
|
+
success: -> { "#{resource.owner} has been successfully updated. Please double check the membership history is correct" },
|
10
|
+
redirect: -> { admin_owners_path(resource) }
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def permitted_params
|
15
|
+
model = (params.key?(:effective_membership) ? :effective_membership : :membership)
|
16
|
+
params.require(model).permit!
|
17
|
+
end
|
18
|
+
|
19
|
+
def admin_owners_path(resource)
|
20
|
+
Effective::Resource.new(resource.owner, namespace: :admin).action_path(:edit) + '?tab=membership'
|
21
|
+
end
|
22
|
+
|
8
23
|
end
|
9
24
|
end
|
@@ -6,7 +6,7 @@ module Admin
|
|
6
6
|
include Effective::CrudController
|
7
7
|
|
8
8
|
resource_scope -> { EffectiveMemberships.Organization.deep.all }
|
9
|
-
datatable -> { EffectiveResources.best('Admin::
|
9
|
+
datatable -> { EffectiveResources.best('Admin::EffectiveOrganizationsDatatable').new }
|
10
10
|
|
11
11
|
private
|
12
12
|
|
@@ -1,31 +1,33 @@
|
|
1
|
-
|
1
|
+
module Admin
|
2
|
+
class EffectiveApplicantReferencesDatatable < Effective::Datatable
|
2
3
|
|
3
|
-
|
4
|
-
|
4
|
+
datatable do
|
5
|
+
order :name
|
5
6
|
|
6
|
-
|
7
|
+
col :applicant
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
col :name
|
10
|
+
col :email
|
11
|
+
col :phone
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
13
|
+
col :status do |reference|
|
14
|
+
if reference.submitted?
|
15
|
+
'Waiting on response'
|
16
|
+
elsif reference.completed?
|
17
|
+
'Completed'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
col :last_notified_at do |reference|
|
22
|
+
reference.last_notified_at&.strftime('%F') unless reference.completed?
|
17
23
|
end
|
18
|
-
end
|
19
24
|
|
20
|
-
|
21
|
-
reference.last_notified_at&.strftime('%F') unless reference.completed?
|
25
|
+
actions_col
|
22
26
|
end
|
23
27
|
|
24
|
-
|
25
|
-
|
28
|
+
collection do
|
29
|
+
Effective::ApplicantReference.deep.all
|
30
|
+
end
|
26
31
|
|
27
|
-
collection do
|
28
|
-
Effective::ApplicantReference.deep.all
|
29
32
|
end
|
30
|
-
|
31
33
|
end
|
@@ -49,8 +49,8 @@ module Admin
|
|
49
49
|
|
50
50
|
raise('expected an owner_id, not user_id') if attributes[:user_id].present?
|
51
51
|
|
52
|
-
if attributes[:owner_id]
|
53
|
-
scope = scope.where(owner_id: attributes[:owner_id])
|
52
|
+
if attributes[:owner_id] && attributes[:owner_type]
|
53
|
+
scope = scope.where(owner_id: attributes[:owner_id], owner_type: attributes[:owner_type])
|
54
54
|
end
|
55
55
|
|
56
56
|
if attributes[:applicant_id]
|
@@ -12,8 +12,6 @@ module Admin
|
|
12
12
|
|
13
13
|
col :owner
|
14
14
|
|
15
|
-
col :number
|
16
|
-
|
17
15
|
col :categories, label: 'Category' do |history|
|
18
16
|
history.categories.map.with_index do |category, index|
|
19
17
|
category_id = history.category_ids[index]
|
@@ -23,6 +21,8 @@ module Admin
|
|
23
21
|
end.join.html_safe
|
24
22
|
end
|
25
23
|
|
24
|
+
col :number
|
25
|
+
|
26
26
|
col :category_ids, visible: false
|
27
27
|
|
28
28
|
col :bad_standing
|
@@ -35,7 +35,11 @@ module Admin
|
|
35
35
|
raise('expected an owner_id, not user_id') if attributes[:user_id].present?
|
36
36
|
|
37
37
|
scope = Effective::MembershipHistory.deep.all
|
38
|
-
|
38
|
+
|
39
|
+
if attributes[:owner_id] && attributes[:owner_type]
|
40
|
+
scope = scope.where(owner_id: attributes[:owner_id], owner_type: attributes[:owner_type])
|
41
|
+
end
|
42
|
+
|
39
43
|
scope
|
40
44
|
end
|
41
45
|
|
@@ -69,8 +69,8 @@ module Admin
|
|
69
69
|
|
70
70
|
raise('expected an owner_id, not user_id') if attributes[:user_id].present?
|
71
71
|
|
72
|
-
if attributes[:owner_id].present?
|
73
|
-
memberships = memberships.where(owner_id: attributes[:owner_id])
|
72
|
+
if attributes[:owner_id].present? && attributes[:owner_type].present?
|
73
|
+
memberships = memberships.where(owner_id: attributes[:owner_id], owner_type: attributes[:owner_type])
|
74
74
|
end
|
75
75
|
|
76
76
|
memberships
|
@@ -265,4 +265,48 @@ module EffectiveMembershipsOwner
|
|
265
265
|
membership_histories.find { |history| (history.start_on..history.end_on).cover?(date) } # Ruby 2.6 supports endless ranges
|
266
266
|
end
|
267
267
|
|
268
|
+
# Point out busted data
|
269
|
+
def membership_history_errors
|
270
|
+
return unless membership.present?
|
271
|
+
return unless membership_histories.present?
|
272
|
+
|
273
|
+
errors = []
|
274
|
+
history = membership_histories.first
|
275
|
+
last_history = membership_histories.last
|
276
|
+
|
277
|
+
# Check membership joined on date matches first history start date
|
278
|
+
if membership.joined_on != history.start_on
|
279
|
+
errors << "The joined date #{membership.joined_on.strftime('%F')} does not match the first history start date of #{history.start_on.strftime('%F')}. Please change the first history start date to #{membership.joined_on.strftime('%F')} or update the joined date above."
|
280
|
+
end
|
281
|
+
|
282
|
+
# Check that there is a membership history row if the registered date is unique
|
283
|
+
if membership.joined_on != membership.registration_on && membership_histories.none? { |mh| mh.start_on == membership.registration_on }
|
284
|
+
errors << "The registered date #{membership.registration_on.strftime('%F')} is missing a history with this date. Please create a history with a start date of #{membership.registration_on.strftime('%F')} or update the registered date above."
|
285
|
+
end
|
286
|
+
|
287
|
+
# Check numbers
|
288
|
+
if membership.number.present? && membership_histories.none? { |history| history.number == membership.number }
|
289
|
+
errors << "The membership number ##{membership.number} is missing a history with this number. Please create a history with the #{membership.number} number or update the membership number above."
|
290
|
+
end
|
291
|
+
|
292
|
+
# Check that the last history does not have an end_on date
|
293
|
+
|
294
|
+
if last_history.end_on.present? && !last_history.removed?
|
295
|
+
errors << "The most recent history must have a blank end date. Please remove the end date of the most recent history entry or create another history."
|
296
|
+
elsif membership_histories.any? { |history| history.end_on.blank? && history != last_history }
|
297
|
+
errors << "The end date must be present for all past histories. Please add the end date to all histories, except the most recent history."
|
298
|
+
elsif !membership_history_continuous?
|
299
|
+
errors << "The start and end dates are overlapping or non-continuous. Please make sure each history start date has a matching history end date"
|
300
|
+
end
|
301
|
+
|
302
|
+
errors
|
303
|
+
end
|
304
|
+
|
305
|
+
def membership_history_continuous?
|
306
|
+
membership_histories.all? do |history|
|
307
|
+
history.end_on.blank? || (history.end_on.present? && history.removed?) || membership_histories.find { |h| h.start_on == history.end_on }.present?
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
|
268
312
|
end
|
@@ -2,6 +2,8 @@ module Effective
|
|
2
2
|
class Membership < ActiveRecord::Base
|
3
3
|
belongs_to :owner, polymorphic: true
|
4
4
|
|
5
|
+
attr_accessor :current_action
|
6
|
+
|
5
7
|
has_many :membership_categories, -> { order(:id) }, inverse_of: :membership, dependent: :delete_all
|
6
8
|
accepts_nested_attributes_for :membership_categories
|
7
9
|
|
@@ -54,7 +56,10 @@ module Effective
|
|
54
56
|
|
55
57
|
before_validation do
|
56
58
|
self.registration_on ||= joined_on
|
57
|
-
|
59
|
+
end
|
60
|
+
|
61
|
+
before_validation(if: -> { number_changed? }) do
|
62
|
+
self.number_as_integer = (Integer(number) rescue nil)
|
58
63
|
end
|
59
64
|
|
60
65
|
validates :number, presence: true, uniqueness: true
|
@@ -66,12 +71,29 @@ module Effective
|
|
66
71
|
self.errors.add(:owner_id, 'must be a memberships owner') unless owner.class.effective_memberships_owner?
|
67
72
|
end
|
68
73
|
|
74
|
+
validate(if: -> { registration_on.present? && joined_on.present? }) do
|
75
|
+
self.errors.add(:registration_on, 'must match or be greater than the joined date') if registration_on < joined_on
|
76
|
+
end
|
77
|
+
|
69
78
|
def self.max_number
|
70
79
|
maximum('number_as_integer') || 0
|
71
80
|
end
|
72
81
|
|
73
82
|
def to_s
|
74
|
-
'membership'
|
83
|
+
return 'membership' if owner.blank?
|
84
|
+
|
85
|
+
summary = [
|
86
|
+
owner.to_s,
|
87
|
+
'is',
|
88
|
+
(categories.to_sentence),
|
89
|
+
'member',
|
90
|
+
"##{number_was}",
|
91
|
+
"who joined #{joined_on&.strftime('%F') || '-'}",
|
92
|
+
("and last registered #{registration_on.strftime('%F')}" if registration_on > joined_on),
|
93
|
+
(". Membership is Not In Good Standing because #{bad_standing_reason}" if bad_standing?)
|
94
|
+
].compact.join(' ')
|
95
|
+
|
96
|
+
(summary + '.').html_safe
|
75
97
|
end
|
76
98
|
|
77
99
|
# We can't use the polymorphic has_many. So this is a helper.
|
@@ -36,5 +36,20 @@ module Effective
|
|
36
36
|
'membership history'
|
37
37
|
end
|
38
38
|
|
39
|
+
# These two accessors are for the memberships history form.
|
40
|
+
# But we just assign categories and category_ids directly in registrar.
|
41
|
+
def membership_categories
|
42
|
+
category_ids.present? ? EffectiveMemberships.Category.where(id: category_ids) : []
|
43
|
+
end
|
44
|
+
|
45
|
+
def membership_category_ids
|
46
|
+
membership_categories.map(&:id)
|
47
|
+
end
|
48
|
+
|
49
|
+
def membership_category_ids=(ids)
|
50
|
+
categories = EffectiveMemberships.Category.where(id: ids)
|
51
|
+
assign_attributes(categories: categories.map(&:to_s), category_ids: categories.map(&:id))
|
52
|
+
end
|
53
|
+
|
39
54
|
end
|
40
55
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
= effective_form_with(model: [:admin, membership_history], engine: true) do |f|
|
2
|
+
- if inline_datatable?
|
3
|
+
= f.hidden_field :owner_id
|
4
|
+
= f.hidden_field :owner_type
|
5
|
+
- else
|
6
|
+
- raise('todo')
|
7
|
+
- collection = EffectiveMembershipsOwner.descendants.map { |d| [d.name.to_s, d.members.sorted] }.to_h
|
8
|
+
= f.select :owner_id, collection, polymorphic: true
|
9
|
+
|
10
|
+
= f.date_field :start_on, hint: 'The start date of this period in history. Must be present.'
|
11
|
+
|
12
|
+
= f.date_field :end_on, hint: 'The end date of this period in history. Must be present for all past histories. Must be blank in the most recent history, unless membership removed.'
|
13
|
+
= f.text_field :number, hint: 'The membership number'
|
14
|
+
= f.select :membership_category_ids, EffectiveMemberships.Category.all.sorted, label: 'Membership Categories', hint: 'The membership category or categories held during this period in history.'
|
15
|
+
|
16
|
+
= f.check_box :bad_standing, hint: 'Membership in bad standing'
|
17
|
+
= f.check_box :removed, hint: 'Membership removed'
|
18
|
+
|
19
|
+
= f.submit 'Update History', border: false, center: true, 'data-confirm': "Really update #{f.object.owner}?"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
- membership ||= owner.membership
|
2
|
+
- owner ||= membership.owner
|
3
|
+
|
4
|
+
- if membership.present?
|
5
|
+
= card('Member Information') do
|
6
|
+
= render 'admin/memberships/form_membership', membership: membership
|
7
|
+
|
8
|
+
= card('History') do
|
9
|
+
= render 'admin/membership_histories/validation', owner: owner
|
10
|
+
= render_datatable(Admin::EffectiveMembershipHistoriesDatatable.new(owner: owner), inline: true, simple: true)
|
11
|
+
|
12
|
+
- # Always render this one
|
13
|
+
= render 'admin/registrar_actions/form', owner: owner
|
14
|
+
|
15
|
+
- if membership.blank? && owner.membership_histories.present?
|
16
|
+
= card('History') do
|
17
|
+
= render_datatable(Admin::EffectiveMembershipHistoriesDatatable.new(owner: owner), inline: true, simple: true)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
= effective_form_with(model: [:admin, membership], engine: true) do |f|
|
2
|
+
= f.hidden_field :owner_id
|
3
|
+
= f.hidden_field :owner_type
|
4
|
+
|
5
|
+
%p.text-muted
|
6
|
+
Change a member's information.
|
7
|
+
|
8
|
+
- f.object.current_action = true if f.errors.present?
|
9
|
+
|
10
|
+
= f.static_field :current_action, label: 'Current Membership' do
|
11
|
+
= membership.to_s
|
12
|
+
|
13
|
+
= f.check_box :current_action, label: 'Yes, update membership information'
|
14
|
+
|
15
|
+
= f.show_if :current_action, true do
|
16
|
+
= f.date_field :joined_on, label: 'Joined', hint: 'When the member first received any membership category'
|
17
|
+
= f.date_field :registration_on, label: 'Registered', hint: 'When the membership category last changed'
|
18
|
+
= f.text_field :number, hint: 'The membership number. Must be unique.'
|
19
|
+
|
20
|
+
%p.text-muted To update the current membership categories, use the 'Assign' or 'Reclassify' actions below
|
21
|
+
|
22
|
+
= f.submit 'Update Membership', border: false, center: true, 'data-confirm': "Really update #{f.object.owner}?"
|
data/config/routes.rb
CHANGED
@@ -43,7 +43,8 @@ EffectiveMemberships::Engine.routes.draw do
|
|
43
43
|
resources :applicant_course_names, except: [:show]
|
44
44
|
|
45
45
|
resources :fee_payments, only: [:index, :show]
|
46
|
-
resources :memberships, only: [:index]
|
46
|
+
resources :memberships, only: [:index, :update]
|
47
|
+
resources :membership_histories, except: [:show]
|
47
48
|
resources :registrar_actions, only: [:create]
|
48
49
|
|
49
50
|
resources :organizations, except: [:show] do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_memberships
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
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: 2022-03-
|
11
|
+
date: 2022-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -247,6 +247,7 @@ files:
|
|
247
247
|
- app/controllers/admin/categories_controller.rb
|
248
248
|
- app/controllers/admin/fee_payments_controller.rb
|
249
249
|
- app/controllers/admin/fees_controller.rb
|
250
|
+
- app/controllers/admin/membership_histories_controller.rb
|
250
251
|
- app/controllers/admin/memberships_controller.rb
|
251
252
|
- app/controllers/admin/organizations_controller.rb
|
252
253
|
- app/controllers/admin/registrar_actions_controller.rb
|
@@ -334,6 +335,10 @@ files:
|
|
334
335
|
- app/views/admin/fee_payments/_fee_payment.html.haml
|
335
336
|
- app/views/admin/fees/_fee.html.haml
|
336
337
|
- app/views/admin/fees/_form.html.haml
|
338
|
+
- app/views/admin/membership_histories/_form.html.haml
|
339
|
+
- app/views/admin/membership_histories/_validation.html.haml
|
340
|
+
- app/views/admin/memberships/_form.html.haml
|
341
|
+
- app/views/admin/memberships/_form_membership.html.haml
|
337
342
|
- app/views/admin/memberships/_status.html.haml
|
338
343
|
- app/views/admin/organizations/_fields.html.haml
|
339
344
|
- app/views/admin/organizations/_form.html.haml
|