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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2648e82170c5076854831eebdbaf7f972cbfeaf69076280253ad345ca1ac53db
4
- data.tar.gz: 385ddec71ae2103c4f33c08dd732b52b13f87535b0a44c11131389c47b854703
3
+ metadata.gz: 885423c81ffcee648c3ad06826b943ed31f9ed059432e9eda6a55b24a0f07ec0
4
+ data.tar.gz: 3b7c8ed91242b0cd0648cdca9f5e9b70af40bc5f7be7fb3ad585dfbe147c7909
5
5
  SHA512:
6
- metadata.gz: a581b0e79010b252b6e12cf3763d67eee879da8e4661f06c456b037dbcb220c1640d424f246c9d8a210e5d89acfe098fd61cc8a39d947aed46b30ca270ce934c
7
- data.tar.gz: e45c087b0f7f9ea6fa7c2f03593b43da7a6d4451e39447d29ebdc7053422856b97dae45a28977cfb759170d5f278fb3046821070072176050fb551e07a1c4ccb
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::EffectiveMembershipsDatatable').new }
9
+ datatable -> { EffectiveResources.best('Admin::EffectiveOrganizationsDatatable').new }
10
10
 
11
11
  private
12
12
 
@@ -1,31 +1,33 @@
1
- class Admin::EffectiveApplicantReferencesDatatable < Effective::Datatable
1
+ module Admin
2
+ class EffectiveApplicantReferencesDatatable < Effective::Datatable
2
3
 
3
- datatable do
4
- order :name
4
+ datatable do
5
+ order :name
5
6
 
6
- col :applicant
7
+ col :applicant
7
8
 
8
- col :name
9
- col :email
10
- col :phone
9
+ col :name
10
+ col :email
11
+ col :phone
11
12
 
12
- col :status do |reference|
13
- if reference.submitted?
14
- 'Waiting on response'
15
- elsif reference.completed?
16
- 'Completed'
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
- col :last_notified_at do |reference|
21
- reference.last_notified_at&.strftime('%F') unless reference.completed?
25
+ actions_col
22
26
  end
23
27
 
24
- actions_col
25
- end
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
- scope = scope.where(owner_id: attributes[:owner_id]) if attributes[:owner_id]
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
- self.number_as_integer ||= (Integer(number) rescue nil)
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,7 @@
1
+ - raise('expected a memberships owner with a membership') unless owner.present? && owner.try(:membership).present?
2
+
3
+ - errors = owner.membership_history_errors
4
+
5
+ - if errors.present?
6
+ - errors.each do |error|
7
+ .mb-2.alert.alert-warning= error
@@ -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
@@ -1,3 +1,3 @@
1
1
  module EffectiveMemberships
2
- VERSION = '0.4.1'
2
+ VERSION = '0.4.2'
3
3
  end
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.1
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-21 00:00:00.000000000 Z
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