Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/admin/dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@
end
end

# Only special payment invitees (not scholarship or other account types).
special_invitees = Payment.current_conference_payments
.where(account_type: %w[special scholarship])
.where(account_type: 'special')
.includes(:user)
.order(created_at: :desc, id: :desc)
.group_by(&:user_id)
Expand Down
2 changes: 2 additions & 0 deletions app/admin/payments.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
filter :payments_conf_year, as: :select,
collection: -> { Payment.order(:conf_year).distinct.pluck(:conf_year) },
label: "Payment Conf Year"
filter :account_type, as: :select,
collection: -> { Payment.order(:account_type).distinct.pluck(:account_type).compact }

index do
selectable_column
Expand Down
11 changes: 10 additions & 1 deletion app/controllers/payments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,17 @@ def generate_hash(current_user, amount=100)
end

def validated_payment_amount(raw_amount)
return nil if raw_amount.respond_to?(:blank?) ? raw_amount.blank? : raw_amount.nil?

amount = Integer(raw_amount, exception: false)
return nil if amount.nil? || amount <= 0
if amount.nil?
begin
amount = BigDecimal(raw_amount.to_s).to_i
rescue ArgumentError
return nil
end
end
return nil if amount <= 0

balance_due = current_balance_due
return nil if balance_due <= 0
Expand Down
6 changes: 3 additions & 3 deletions spec/controllers/payments_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -168,10 +168,10 @@
end

context 'with different amounts' do
it 'rejects decimal amounts' do
it 'truncates dollar-and-cent strings to whole dollars (Nelnet uses integer dollars)' do
post :make_payment, params: { amount: '50.50' }
expect(response).to redirect_to(all_payments_path)
expect(flash[:alert]).to eq('Please enter a valid payment amount.')
expect(response).to be_redirect
expect(response.location).to include('amountDue=5000')
end

it 'rejects zero amount' do
Expand Down
10 changes: 1 addition & 9 deletions spec/requests/admin_dashboard_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,8 @@
)

special_user = create(:user, email: 'special@example.com')
scholarship_user = create(:user, email: 'scholarship@example.com')
other_user = create(:user, email: 'other@example.com')

create(:payment, :special, user: special_user, conf_year: application_setting.contest_year)
create(:payment, :scholarship, user: scholarship_user, conf_year: application_setting.contest_year)
create(:payment, user: other_user, conf_year: application_setting.contest_year)

application = create(
:application,
Expand All @@ -54,15 +50,11 @@
get admin_root_path

expect(response).to be_successful
expect(response.body).to include('Special invitees (2)')
expect(response.body).to include('Special invitees (1)')
expect(response.body).to include('special@example.com')
expect(response.body).to include('scholarship@example.com')
expect(response.body).to include('Needs to submit an application to')
expect(response.body).to include('special')
expect(response.body).to include('scholarship')
expect(response.body).to include("href=\"#{admin_application_path(application)}\"")
expect(response.body).to include('Ada Lovelace')
expect(response.body.index('scholarship@example.com')).to be < response.body.index('special@example.com')
end
end
end
122 changes: 122 additions & 0 deletions spec/requests/conference_closed_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# frozen_string_literal: true

require 'rails_helper'

# Opt out of spec/support/application_setting_mock.rb and application_mock.rb so views use real
# ApplicationSetting rows and Application.active_conference_applications (see those files).
RSpec.describe 'Conference closed page', type: :request, real_application_settings: true do
# Avoid multiple active ApplicationSetting rows: get_current_app_settings uses active.first (unordered).
before { ApplicationSetting.delete_all }

let(:conf_year) { Time.current.year }
let(:user) { create(:user, email: "conference-closed-#{SecureRandom.hex(8)}@example.com") }
let!(:lodging) { create(:lodging, description: 'Standard', cost: 100.0) }
let(:partner_registration) { create(:partner_registration, cost: 75.0) }

let!(:application_setting) do
create(
:application_setting,
active_application: true,
contest_year: conf_year,
opendate: 1.month.ago,
application_open_period: 48,
application_closed_directions: '<p>UniqueClosedDirectionsHtml</p>',
registration_fee: 50.0
)
end

def create_active_application(offer_status:)
create(
:application,
user: user,
email: user.email,
email_confirmation: user.email,
conf_year: application_setting.contest_year,
offer_status: offer_status,
partner_registration: partner_registration,
lodging_selection: 'Standard'
)
end

describe 'GET /conference_closed' do
context 'when the user is signed in with an offer and no payments' do
before { sign_in user }

%w[registration_offered registration_accepted].each do |status|
it "shows the application fee payment button when offer_status is #{status}" do
create_active_application(offer_status: status)

get conference_closed_path

expect(response).to be_successful
expect(response.body).to include('To accept your offer')
expect(response.body).to include('Pay the Application Fee')
expect(response.body).to include('make_payment')
end
end
end

context 'when the user is signed in with an offer but already has a conference payment' do
before { sign_in user }

it 'shows the payments sidebar message instead of the pay button' do
create_active_application(offer_status: 'registration_offered')
create(
:payment,
:current_conference,
user: user,
transaction_status: '1',
conf_year: application_setting.contest_year
)

get conference_closed_path

expect(response).to be_successful
expect(response.body).to include(
"You may use the links in the 'Your Details' box to the right to view or manage your payments."
)
expect(response.body).not_to include('Pay the Application Fee')
end
end

context 'when the user is signed in but offer_status is not offered or accepted' do
before { sign_in user }

it 'shows application_closed_directions instead of the pay button' do
create_active_application(offer_status: 'not_offered')

get conference_closed_path

expect(response).to be_successful
expect(response.body).to include('UniqueClosedDirectionsHtml')
expect(response.body).not_to include('Pay the Application Fee')
end
end

context 'when opendate is in the future (pre-open messaging)' do
before do
sign_in user
application_setting.update!(opendate: 1.month.from_now)
create_active_application(offer_status: 'registration_offered')
end

it 'shows the upcoming application window copy, not the pay button' do
get conference_closed_path

expect(response).to be_successful
expect(response.body).to include('Thank you for your interest in Bear River.')
expect(response.body).not_to include('Pay the Application Fee')
end
end

context 'when the visitor is not signed in' do
it 'shows application_closed_directions' do
get conference_closed_path

expect(response).to be_successful
expect(response.body).to include('UniqueClosedDirectionsHtml')
expect(response.body).not_to include('Pay the Application Fee')
end
end
end
end
8 changes: 8 additions & 0 deletions spec/requests/payments_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@
expect(response).to redirect_to("https://payment-url.example.com")
end

it "accepts whole-dollar amounts formatted like decimals (e.g. registration_fee from DB)" do
expect_any_instance_of(PaymentsController)
.to receive(:generate_hash).with(user, 50).and_return("https://payment-url.example.com")

post make_payment_path, params: { amount: "50.0" }
expect(response).to redirect_to("https://payment-url.example.com")
end

it "rejects missing amount input" do
post make_payment_path, params: { amount: "" }
expect(response).to redirect_to(all_payments_path)
Expand Down
6 changes: 4 additions & 2 deletions spec/support/application_mock.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
RSpec.configure do |config|
config.before(:each, type: :request) do
config.before(:each, type: :request) do |example|
# Skip mock when testing admin applications index (needs real ActiveRecord chain)
next if RSpec.current_example.metadata[:no_application_mock]
next if example.metadata[:no_application_mock]
# Skip when using real ApplicationSetting rows (same examples need real scopes; see conference_closed_spec)
next if example.metadata[:real_application_settings]

# Create a mock for Application.active_conference_applications
mock_active_applications = double("ActiveApplications")
Expand Down
5 changes: 4 additions & 1 deletion spec/support/application_setting_mock.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
RSpec.configure do |config|
config.before(:each, type: :request) do
config.before(:each, type: :request) do |example|
# Tag examples with `real_application_settings: true` (or `:real_application_settings`) to use DB rows.
next if example.metadata[:real_application_settings]

# Create a mock ApplicationSetting object
mock_app_setting = double("ApplicationSetting",
contest_year: Time.current.year,
Expand Down
Loading