effective_memberships 0.16.1 → 0.17.0

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: f05f20be1f211e1d0a3d17270820752b3015ac6790c635c32973c6c928b2f1b1
4
- data.tar.gz: b8273500b7e6af71968a2ed83195a5a380f0563ab2750c1b6a0624e87ec5c9e5
3
+ metadata.gz: '09fbb8a22bb53806fe272999514bc8cc4d8b8cf5784aaab5428777ffe43af61e'
4
+ data.tar.gz: cc6fd66a60a0db18c98a44849e3768e8c6d892b6af9cd297485b18f65290457b
5
5
  SHA512:
6
- metadata.gz: c298a6e323ce94af492a00ed1aa8addfd1777a1b2023f7715f66d0231868e813d09f59b13adcb14d80da2519b3bf294b52c4eb68ff08c1c466d07a5b257c1ccd
7
- data.tar.gz: c7bcfdb569352928092df90df69ec4fcd735354e71a68676721c139eb1f38b5f7bd0b874bdacadebb641309ff7c1cb425c570a31d806d9ffe227082650c5e7cf
6
+ metadata.gz: e286896d066c61cb0bb65b325837152d275f43c158e0f8df95302c36aee81ef1fcd3359efd37a71ec3f78b182a87fa0ee587c6ffe017d3971013af32b3647e67
7
+ data.tar.gz: 37c79f3c9a254275346c352832082bf9014690144720fd3ea2fef642dfe2740f3e72f3597870754f4c0076574ade33c65a1227d8fefa4f2325903aaacef9bd7f
@@ -35,9 +35,14 @@ module Admin
35
35
  col :qb_item_name, visible: false
36
36
 
37
37
  col :create_renewal_fees, visible: false
38
+ col :create_early_fees, visible: false
38
39
  col :create_late_fees, visible: false
39
40
  col :create_not_in_good_standing, visible: false
40
41
 
42
+ col :renewal_fee, as: :price, visible: false
43
+ col :early_fee, as: :price, visible: false
44
+ col :late_fee, as: :price, visible: false
45
+
41
46
  col :category_type, search: EffectiveMemberships.Category.category_types, visible: false
42
47
 
43
48
  col :optional_applicant_wizard_steps, label: 'Applicant Steps', visible: false
@@ -99,13 +99,19 @@ module EffectiveMembershipsCategory
99
99
  fee_payment_wizard_steps :text
100
100
  fee_payment_cpd_step_requirement :string
101
101
 
102
- # Renewals
102
+ # Renewal Fees
103
103
  create_renewal_fees :boolean
104
104
  renewal_fee :integer
105
105
 
106
+ # Early Fees
107
+ create_early_fees :boolean
108
+ early_fee :integer
109
+
110
+ # Late Fees
106
111
  create_late_fees :boolean
107
112
  late_fee :integer
108
113
 
114
+ # NIGS Status
109
115
  create_not_in_good_standing :boolean
110
116
 
111
117
  # Pricing
@@ -167,6 +173,19 @@ module EffectiveMembershipsCategory
167
173
  validates :qb_item_name, presence: true
168
174
  validates :tax_exempt, inclusion: { in: [true, false] }
169
175
  end
176
+
177
+ with_options(if: -> { create_renewal_fees? }) do
178
+ validates :renewal_fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
179
+ end
180
+
181
+ with_options(if: -> { create_early_fees? }) do
182
+ validates :early_fee, presence: true, numericality: { less_than_or_equal_to: 0 }
183
+ end
184
+
185
+ with_options(if: -> { create_late_fees? }) do
186
+ validates :late_fee, presence: true, numericality: { greater_than_or_equal_to: 0 }
187
+ end
188
+
170
189
  end
171
190
 
172
191
  # Instance Methods
@@ -304,6 +304,34 @@ module EffectiveMembershipsOwner
304
304
  fee
305
305
  end
306
306
 
307
+ def build_early_fee(category:, period:)
308
+ raise('must have an existing membership') unless membership.present?
309
+
310
+ # Return existing but do not build yet
311
+ fee = fees.find { |fee| fee.fee_type == 'Early' && fee.period == period && fee.category_id == category.id && fee.category_type == category.class.name }
312
+ return fee if fee&.purchased?
313
+
314
+ # Only continue if there is an early renewal fee for the same period
315
+ renewal_fee = fees.find { |fee| fee.fee_type == 'Renewal' && fee.period == period && fee.category_id == category.id && fee.category_type == category.class.name }
316
+ return if fee.blank? && (renewal_fee.blank? || renewal_fee.early? == false)
317
+
318
+ # Build the early fee
319
+ fee ||= fees.build()
320
+
321
+ fee.assign_attributes(
322
+ fee_type: 'Early',
323
+ category: category,
324
+ period: period,
325
+ price: category.early_fee.to_i,
326
+ tax_exempt: category.tax_exempt,
327
+ qb_item_name: category.qb_item_name
328
+ )
329
+
330
+ after_build_fee(fee)
331
+
332
+ fee
333
+ end
334
+
307
335
  def build_late_fee(category:, period:)
308
336
  raise('must have an existing membership') unless membership.present?
309
337
 
@@ -24,7 +24,7 @@ module EffectiveMembershipsRegistrar
24
24
  end
25
25
 
26
26
  def late_fee_date(period:)
27
- Time.zone.local(period.year, 2, 1) # Fees are late after February 1st
27
+ Time.zone.local(period.year, 2, 1) # Fees are late after February 1st.
28
28
  raise('to be implemented by app registrar')
29
29
  end
30
30
 
@@ -33,6 +33,22 @@ module EffectiveMembershipsRegistrar
33
33
  raise('to be implemented by app registrar')
34
34
  end
35
35
 
36
+ # The early fee dates are calculated based on period
37
+ # The period is a date that starts on Jan 1st of a year.
38
+ # When Time.zone.now is December the period will be one ahead.
39
+
40
+ # Assumed to be the same as renewal_fee_date
41
+ def early_fee_date(period:)
42
+ Time.zone.local(period.year - 1, 12, 1) # Fees roll over every December 1st
43
+ raise('to be implemented by app registrar')
44
+ end
45
+
46
+ # Assumed to be just before the period actually starts
47
+ def early_fee_end_date(period:)
48
+ Time.zone.local(period.year - 1, 12, 31) # Early fees are destroyed on December 31st
49
+ raise('to be implemented by app registrar')
50
+ end
51
+
36
52
  # A renewal fee must be at least this old to be considered late?
37
53
  # Must be less than (late_fee_date - renewal_fee_date) but this is not enforced
38
54
  def min_late_duration
@@ -112,6 +128,10 @@ module EffectiveMembershipsRegistrar
112
128
  periods(from: from, to: to).reverse.map { |period| [period_end_on(date: period), period] }
113
129
  end
114
130
 
131
+ def early_fee_date_range(period:)
132
+ (early_fee_date(period: period).beginning_of_day)..(early_fee_end_date(period: period).beginning_of_day)
133
+ end
134
+
115
135
  # Category is required, statuses are optional
116
136
  def assign!(owner, categories:, statuses: nil, date: nil, number: nil)
117
137
  categories = Array(categories)
@@ -492,31 +512,48 @@ module EffectiveMembershipsRegistrar
492
512
  # rake effective_memberships:create_fees
493
513
  # Create Renewal and Late fees
494
514
  # Assigns NIGS
495
- def create_all_fees!(period: nil)
515
+ def create_all_fees!(period: nil, force: false)
496
516
  period ||= current_period
497
517
  memberships = Effective::Membership.deep.with_unpaid_fees_through(period)
498
518
 
499
519
  memberships.find_each do |membership|
500
- create_fees!(membership, period: period); GC.start
520
+ create_fees!(membership, period: period, force: force); GC.start
501
521
  end
502
522
 
503
523
  true
504
524
  end
505
525
 
506
- def create_fees!(resource, period: nil)
526
+ def create_fees!(resource, period: nil, force: false)
527
+ today = Time.zone.now.beginning_of_day
507
528
  period ||= current_period
508
529
 
509
530
  membership = (resource.class.respond_to?(:effective_memberships_owner?) ? resource.membership : resource)
510
531
  raise('expected a membership') unless membership.present? && membership.kind_of?(Effective::Membership)
511
532
 
512
533
  # Create Renewal Fees
513
- create_renewal_fees!(membership, period: period)
534
+ if force || today == renewal_fee_date(date: today)
535
+ create_renewal_fees!(membership, period: period)
536
+ end
537
+
538
+ # Create Early Fees
539
+ if force || today == early_fee_date(period: period)
540
+ create_early_fees!(membership, period: period)
541
+ end
542
+
543
+ # Destroy Early Fees
544
+ if force || today == early_fee_end_date(period: period)
545
+ destroy_early_fees!(membership, period: period)
546
+ end
514
547
 
515
548
  # Create Late Fees
516
- create_late_fees!(membership, period: period)
549
+ if force || today == late_fee_date(period: period)
550
+ create_late_fees!(membership, period: period)
551
+ end
517
552
 
518
553
  # Update Membership Status - Assign Not In Good Standing
519
- create_not_in_good_standing!(membership, period: period)
554
+ if force || today == not_in_good_standing_date(period: period)
555
+ create_not_in_good_standing!(membership, period: period)
556
+ end
520
557
 
521
558
  true
522
559
  end
@@ -536,6 +573,28 @@ module EffectiveMembershipsRegistrar
536
573
  end
537
574
  end
538
575
 
576
+ def create_early_fees!(membership, period:)
577
+ membership.categories.select(&:create_early_fees?).map do |category|
578
+ fee = membership.owner.build_early_fee(category: category, period: period)
579
+ next if fee.blank? || fee.persisted?
580
+
581
+ puts("Created early fee for #{membership.owner}") if debug?
582
+
583
+ fee.save!
584
+ end
585
+ end
586
+
587
+ def destroy_early_fees!(membership, period:)
588
+ membership.categories.select(&:create_early_fees?).map do |category|
589
+ fee = membership.owner.build_early_fee(category: category, period: period)
590
+ next if fee.blank? || fee.early? || fee.purchased? || fee.deferred?
591
+
592
+ puts("Destroyed early fee for #{membership.owner}") if debug?
593
+
594
+ fee.destroy!
595
+ end
596
+ end
597
+
539
598
  def create_late_fees!(membership, period:)
540
599
  membership.categories.select(&:create_late_fees?).map do |category|
541
600
  fee = membership.owner.build_late_fee(category: category, period: period)
@@ -548,7 +607,6 @@ module EffectiveMembershipsRegistrar
548
607
  end
549
608
 
550
609
  def create_not_in_good_standing!(membership, period:)
551
- return unless Time.zone.now.beginning_of_day == not_in_good_standing_date(period: period).beginning_of_day
552
610
  return unless membership.categories.any?(&:create_not_in_good_standing?)
553
611
 
554
612
  membership.owner.update_membership_status!
@@ -92,6 +92,11 @@ module Effective
92
92
  title.presence || default_title()
93
93
  end
94
94
 
95
+ def early?
96
+ return false if purchased?
97
+ EffectiveMemberships.Registrar.early_fee_date_range(period: period).cover?(Time.zone.now)
98
+ end
99
+
95
100
  def late?
96
101
  return false if late_on.blank?
97
102
  return false if purchased?
@@ -144,10 +149,6 @@ module Effective
144
149
  ['Prorated', 'Renewal'].include?(fee_type)
145
150
  end
146
151
 
147
- def renewal_fee?
148
- fee_type == 'Renewal'
149
- end
150
-
151
152
  def custom_fee?
152
153
  EffectiveMemberships.custom_fee_types.include?(fee_type)
153
154
  end
@@ -306,7 +306,7 @@ module Effective
306
306
 
307
307
  # Otherwise build fees right now
308
308
  EffectiveMemberships.Registrar.delete_fees!(self)
309
- EffectiveMemberships.Registrar.create_fees!(self, period: period)
309
+ EffectiveMemberships.Registrar.create_fees!(self, period: period, force: true)
310
310
 
311
311
  true
312
312
  end
@@ -15,5 +15,13 @@ module Effective
15
15
  Time.zone.local(period.year, 3, 1) # Membership are Not In Good Standing after March 1st
16
16
  end
17
17
 
18
+ def early_fee_date(period:)
19
+ Time.zone.local(period.year - 1, 12, 1) # Fees roll over every December 1st
20
+ end
21
+
22
+ def early_fee_end_date(period:)
23
+ Time.zone.local(period.year - 1, 12, 31) # Early fees are destroyed on December 31st
24
+ end
25
+
18
26
  end
19
27
  end
@@ -0,0 +1,14 @@
1
+ %h3= ets('effective_memberships.fees.early')
2
+
3
+ = f.check_box :create_early_fees, label: "Yes, #{ets('effective_memberships.fees.early')} should be created"
4
+
5
+ = f.show_if(:create_early_fees, true) do
6
+ - period = EffectiveMemberships.Registrar.current_period
7
+ - date = EffectiveMemberships.Registrar.early_fee_date(period: period)
8
+ - end_date = EffectiveMemberships.Registrar.early_fee_end_date(period: period)
9
+
10
+ %p Charged to members, between #{date.strftime('%B %e')} and #{end_date.strftime('%B %e')}, with outstanding renewal dues.
11
+
12
+ .row
13
+ .col-md-3
14
+ = f.price_field :early_fee, hint: 'Expecting a price less than zero. Please enter the early fee discount from the regular price'
@@ -1,5 +1,6 @@
1
- %h3 Late Fees
2
- = f.check_box :create_late_fees, label: 'Yes, late fees should be created'
1
+ %h3= ets('effective_memberships.fees.late')
2
+
3
+ = f.check_box :create_late_fees, label: "Yes, #{ets('effective_memberships.fees.late')} should be created"
3
4
 
4
5
  = f.show_if(:create_late_fees, true) do
5
6
  - period = EffectiveMemberships.Registrar.current_period
@@ -7,4 +8,4 @@
7
8
 
8
9
  %p Charged to members, on #{date.strftime('%B %e')}, with outstanding renewal dues or other fees.
9
10
  .row
10
- .col-3= f.price_field :late_fee
11
+ .col-md-3= f.price_field :late_fee
@@ -1,5 +1,5 @@
1
- %h3 Renewal Fees
2
- = f.check_box :create_renewal_fees, label: 'Yes, annual renewal fees should be created'
1
+ %h3= ets('effective_memberships.fees.renewal')
2
+ = f.check_box :create_renewal_fees, label: "Yes, #{ets('effective_memberships.fees.renewal')} should be created"
3
3
 
4
4
  = f.show_if(:create_renewal_fees, true) do
5
5
  - date = EffectiveMemberships.Registrar.renewal_fee_date(date: Time.zone.now)
@@ -1,7 +1,20 @@
1
1
  = effective_form_with(model: [:admin, category], engine: true) do |f|
2
2
  = render('admin/categories/fees_applicant', f: f)
3
- = render('admin/categories/fees_renewal', f: f)
4
- = render('admin/categories/fees_late', f: f)
3
+
4
+ - now = Time.zone.now
5
+
6
+ - if EffectiveMemberships.Registrar.renewal_fee_date(date: now).present?
7
+ = render('admin/categories/fees_renewal', f: f)
8
+
9
+ - if EffectiveMemberships.Registrar.early_fee_date(period: now).present?
10
+ = render('admin/categories/fees_early', f: f)
11
+
12
+ - if EffectiveMemberships.Registrar.late_fee_date(period: now).present?
13
+ = render('admin/categories/fees_late', f: f)
14
+
5
15
  = render('admin/categories/fees_additional', f: f)
6
- = render('admin/categories/fees_nigs', f: f)
16
+
17
+ - if EffectiveMemberships.Registrar.not_in_good_standing_date(period: now).present?
18
+ = render('admin/categories/fees_nigs', f: f)
19
+
7
20
  = f.submit
@@ -0,0 +1 @@
1
+ = f.check_box :declare_resignation, label: "Yes, I am applying for resignation from #{f.object.category}"
@@ -8,8 +8,6 @@
8
8
  = effective_form_with(model: resource, url: wizard_path(step), method: :put) do |f|
9
9
  = f.hidden_field :id
10
10
 
11
- = render_if_exists("effective/applicants/resignation_fields", f: f)
12
-
13
- = f.check_box :declare_resignation, label: "Yes, I am applying for resignation from #{f.object.category}"
11
+ = render("effective/applicants/resignation_fields", f: f)
14
12
 
15
13
  = f.save 'Save and Continue'
@@ -8,6 +8,7 @@ en:
8
8
  prorated: 'Prorated Fee'
9
9
  reinstatement: 'Reinstatement Fee'
10
10
  renewal: 'Renewal Fee'
11
+ early: 'Early Fee'
11
12
  late: 'Late Fee'
12
13
  discount: 'Discount Fee'
13
14
  admin: 'Admin Fee'
@@ -52,6 +52,9 @@ class CreateEffectiveMemberships < ActiveRecord::Migration[6.0]
52
52
  t.boolean :create_renewal_fees, default: false
53
53
  t.integer :renewal_fee
54
54
 
55
+ t.boolean :create_early_fees, default: false
56
+ t.integer :early_fee
57
+
55
58
  t.boolean :create_late_fees, default: false
56
59
  t.integer :late_fee
57
60
 
@@ -1,3 +1,3 @@
1
1
  module EffectiveMemberships
2
- VERSION = '0.16.1'
2
+ VERSION = '0.17.0'
3
3
  end
@@ -58,7 +58,7 @@ module EffectiveMemberships
58
58
  end
59
59
 
60
60
  def self.fee_types
61
- required = ['Applicant', 'Reinstatement', 'Prorated', 'Discount', 'Renewal', 'Late', 'Admin']
61
+ required = ['Applicant', 'Reinstatement', 'Prorated', 'Discount', 'Renewal', 'Early', 'Late', 'Admin']
62
62
  additional = Array(additional_fee_types)
63
63
 
64
64
  (required + additional).uniq.sort
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.16.1
4
+ version: 0.17.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: 2023-04-25 00:00:00.000000000 Z
11
+ date: 2023-04-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -367,6 +367,7 @@ files:
367
367
  - app/views/admin/applicants/_status.html.haml
368
368
  - app/views/admin/categories/_fees_additional.html.haml
369
369
  - app/views/admin/categories/_fees_applicant.html.haml
370
+ - app/views/admin/categories/_fees_early.html.haml
370
371
  - app/views/admin/categories/_fees_late.html.haml
371
372
  - app/views/admin/categories/_fees_nigs.html.haml
372
373
  - app/views/admin/categories/_fees_renewal.html.haml
@@ -458,6 +459,7 @@ files:
458
459
  - app/views/effective/applicants/_reinstatement.html.haml
459
460
  - app/views/effective/applicants/_reinstatement_fields.html.haml
460
461
  - app/views/effective/applicants/_resignation.html.haml
462
+ - app/views/effective/applicants/_resignation_fields.html.haml
461
463
  - app/views/effective/applicants/_select.html.haml
462
464
  - app/views/effective/applicants/_select_organization.html.haml
463
465
  - app/views/effective/applicants/_stamp.html.haml