diff --git a/README.md b/README.md index b20249273..4d14857cd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,13 @@ +[![Maintainability](https://api.codeclimate.com/v1/badges/f023aeddae42d2da37ba/maintainability)](https://codeclimate.com/github/armandofox/audience1st/maintainability) +![Build Status](https://github.com/armandofox/audience1st/actions/workflows/ci.yml/badge.svg) +[![Test Coverage](https://api.codeclimate.com/v1/badges/f023aeddae42d2da37ba/test_coverage)](https://codeclimate.com/github/armandofox/audience1st/test_coverage) +[![Pivotal Tracker](https://github.com/armandofox/audience1st/blob/main/app/assets/images/pivotal_tracker_logo.png)](https://pivotaltracker.com/n/projects/44802) + +Spring 24 Team Badges [![Maintainability](https://api.codeclimate.com/v1/badges/d9b6e16a95d868605440/maintainability)](https://codeclimate.com/github/cs169/audience1st/maintainability) ![Build Status](https://github.com/cs169/audience1st/actions/workflows/ci.yml/badge.svg) [![Test Coverage](https://api.codeclimate.com/v1/badges/d9b6e16a95d868605440/test_coverage)](https://codeclimate.com/github/cs169/audience1st/test_coverage) -[![Pivotal Tracker](https://github.com/armandofox/audience1st/blob/main/app/assets/images/pivotal_tracker_logo.png)](https://pivotaltracker.com/n/projects/44802) +[![Pivotal Tracker](https://github.com/armandofox/audience1st/blob/main/app/assets/images/pivotal_tracker_logo.png)](https://www.pivotaltracker.com/n/projects/2488109) Audience1st was written by [Armando Fox](https://github.com/armandofox) with contributions from: diff --git a/app/controllers/options_controller.rb b/app/controllers/options_controller.rb index c5ccf02b9..5458c61cd 100644 --- a/app/controllers/options_controller.rb +++ b/app/controllers/options_controller.rb @@ -1,7 +1,7 @@ class OptionsController < ApplicationController before_filter :is_admin_filter - + def index @o = Option.first end @@ -15,8 +15,6 @@ def update option_params['advance_sales_cutoff'].to_i * params['before_or_after'].to_i # if there is a file upload for HTML template, get it option_params['html_email_template'] = params['html_email_template'].read unless params['html_email_template'].blank? - # if recurring donations not allowed, set default_donation_type to one time - option_params['default_donation_type'] = 'one' unless option_params['allow_recurring_donations'] == 'true' if (@o.update_attributes(option_params)) redirect_to options_path, :notice => "Update successful." else diff --git a/app/controllers/store_controller.rb b/app/controllers/store_controller.rb index f47dfa590..e6cf27f38 100644 --- a/app/controllers/store_controller.rb +++ b/app/controllers/store_controller.rb @@ -1,13 +1,12 @@ class StoreController < ApplicationController include StoreHelper - skip_before_filter :verify_authenticity_token, :only => %w(show_changed showdate_changed) before_filter :set_customer, :except => %w[process_donation] before_filter :is_logged_in, :only => %w[checkout place_order] before_filter :order_is_not_empty, :only => %w[shipping_address checkout place_order] - + # ACTION INVARIANT BEFORE ACTION # ------ ----------------------- # index, subscribe, donate_to_fund valid @customer @@ -41,7 +40,7 @@ def set_customer redirect_customer = resolve_customer_in_url(logged_in_user, specified_customer) if redirect_customer == specified_customer # ok to proceed as is @customer = specified_customer - else + else redirect_to url_for(params.merge(:customer_id => redirect_customer.id, :only_path => true)) end end @@ -103,11 +102,11 @@ def subscribe redirect_to(store_path(@customer), :alert => "There are no subscriptions on sale at this time.") if @subs_to_offer.empty? end - def donate_to_fund - return_after_login params.except(:customer_id) - @account_code = AccountCode.find_by_code(params[:id]) || - AccountCode.find_by_id(params[:id]) || - AccountCode.default_account_code + def donate_to_fund_redirect + # redirect donate_to_fund route to quickdonate for potential printed material with donate_to_fund url + fund_code = params[:id] + fund_code = Donation.default_code.code if fund_code.blank? + redirect_to quick_donate_url(account_code_string: fund_code) end # Serve quick_donate page; POST calls #process_donation @@ -118,22 +117,39 @@ def donate @customer = Customer.new session[:guest_checkout] = true end + # account_code_string is valid + if params[:account_code_string] && !AccountCode.where(code: params[:account_code_string]).empty? + @account_code_string = params[:account_code_string] + @account_code_info = AccountCode.find_by_code(@account_code_string) + @account_code_name = @account_code_info.name + @account_code_description = @account_code_info.description + elsif params[:account_code_string].nil? # account_code_string is nil, so redirect with default code inserted into url + return redirect_to(quick_donate_path(:customer_id => @customer.id, :account_code_string => Donation.default_code.code)) + else # account_code_string is invalid, so redirect with default code inserted into url + display error message + return redirect_to(quick_donate_path(:customer_id => @customer.id, :account_code_string => Donation.default_code.code), :alert => "Invalid Fund ID") + end end def process_donation @amount = to_numeric(params[:donation]) + @account_code = AccountCode.where(code: params[:account_code_string])[0] || Donation.default_code if params[:customer_id].blank? customer_params = params.require(:customer).permit(Customer.user_modifiable_attributes) @customer = Customer.for_donation(customer_params) - @customer.errors.empty? or return redirect_to(quick_donate_path(:customer => params[:customer], :donation => @amount), :alert => "Incomplete or invalid donor information: #{@customer.errors.as_html}") + @customer.errors.empty? or return redirect_to( + quick_donate_path( + :customer => params[:customer], + :account_code_string => @account_code.code, + :donation => @amount), + :alert => "Incomplete or invalid donor information: #{@customer.errors.as_html}") else # we got here via a logged-in customer @customer = Customer.find params[:customer_id] end # At this point, the customer has been persisted, so future redirects just use the customer id. - redirect_route = quick_donate_path(:customer_id => @customer.id, :donation => @amount) + redirect_route = quick_donate_path(:customer_id => @customer.id, :account_code_string => @account_code.code, :donation => @amount) @amount > 0 or return redirect_to(redirect_route, :alert => 'Donation amount must be provided') # Given valid donation, customer, and charge token, create & place credit card order. - @gOrderInProgress = Order.new_from_donation(@amount, Donation.default_code, @customer) + @gOrderInProgress = Order.new_from_donation(@amount, @account_code, @customer) @gOrderInProgress.purchasemethod = Purchasemethod.get_type_by_name('web_cc') @gOrderInProgress.purchase_args = {:credit_card_token => params[:credit_card_token]} @gOrderInProgress.processed_by = @customer @@ -195,10 +211,10 @@ def shipping_address recipient = recipient_from_params(customer_params) @recipient = recipient[0] if @recipient.email == @customer.email - flash.now[:alert] = I18n.t('store.errors.gift_diff_email_notice') + flash.now[:alert] = I18n.t('store.errors.gift_diff_email_notice') render :action => :shipping_address return - end + end if Customer.email_matches_diff_last_name?(try_customer) flash.now[:alert] = I18n.t('store.errors.gift_matching_email_diff_last_name') render :action => :shipping_address @@ -219,7 +235,7 @@ def shipping_address if Customer.email_last_name_match_diff_address?(try_customer) flash[:notice] = I18n.t('store.gift_matching_email_last_name_diff_address') elsif recipient_from_params(customer_params)[1] == "found_matching_customer" - flash[:notice] = I18n.t('store.gift_recipient_on_file') + flash[:notice] = I18n.t('store.gift_recipient_on_file') end redirect_to_checkout end @@ -304,7 +320,7 @@ def referer_target promo_code_args = (@promo.blank? ? {} : {:promo_code => @promo}) redirect_target = case params[:referer].to_s - when 'donate' then quick_donate_path # no @customer assumed + when 'donate' then quick_donate_path(:account_code_string => params[:account_code_string]) # no @customer assumed when 'donate_to_fund' then donate_to_fund_path(params[:account_code_id], @customer) when 'subscribe' then store_subscribe_path(@customer,promo_code_args) when 'index' then store_path(@customer, promo_code_args.merge(:what => params[:what], :showdate_id => params[:showdate_id])) diff --git a/app/views/account_codes/index.html.haml b/app/views/account_codes/index.html.haml index 72824d6a7..482f4f23b 100644 --- a/app/views/account_codes/index.html.haml +++ b/app/views/account_codes/index.html.haml @@ -11,7 +11,7 @@ %td= link_to account_code.code, edit_account_code_path(account_code) %td= link_to account_code.name, edit_account_code_path(account_code) %td= [account_code.description, account_code.donation_prompt].join('
'.html_safe).html_safe - %td= purchase_link_popup link_icon, donate_to_fund_url(account_code.id), "donations to #{account_code.name_with_code}" + %td= purchase_link_popup link_icon, quick_donate_url(account_code_string: account_code.code), "donations to #{account_code.name_with_code}" %br = link_to 'Add New Account Code...', new_account_code_path , :class => 'btn btn-primary' diff --git a/app/views/store/donate.html.haml b/app/views/store/donate.html.haml index 065f1d869..968dc2dae 100644 --- a/app/views/store/donate.html.haml +++ b/app/views/store/donate.html.haml @@ -26,12 +26,13 @@ #store #quick_donation - %h1.text-center= sanitize(Option.quick_donation_banner) - %p.text-center.lead-= sanitize(Option.quick_donation_explanation) + %h1.text-center= @account_code_name + %p.text-center.lead-= @account_code_description = form_tag(process_donation_path, {:id => '_stripe_payment_form', :onsubmit => 'return confirmAndSubmit()' }) do = hidden_field_tag 'referer', 'donate' = hidden_field_tag 'customer_id', @customer.id + = hidden_field_tag 'account_code_string', @account_code_string #billing= render :partial => 'customers/billing_address', :locals => {:customer => @customer} %fieldset#donation_info diff --git a/config/routes.rb b/config/routes.rb index 522344c7c..41122a906 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -112,7 +112,8 @@ get '/store/(:customer_id)' => 'store#index', :defaults => {:customer_id => nil}, :as => 'store' get '/subscribe/(:customer_id)' => 'store#subscribe', :defaults => {:customer_id => nil}, :as => 'store_subscribe' - get '/donate_to_fund/:id/(:customer_id)' => 'store#donate_to_fund', :defaults => {:customer_id => nil}, :as => 'donate_to_fund' + # get '/donate_to_fund/:id/(:customer_id)' => 'store#donate_to_fund', :defaults => {:customer_id => nil}, :as => 'donate_to_fund' + get '/donate_to_fund/(:id)/(:customer_id)', :defaults => {:customer_id => nil}, to: 'store#donate_to_fund_redirect' get '/store/cancel' => 'store#cancel', :as => 'store_cancel' # subsequent actions in the above flow require a customer_id in the URL: diff --git a/db/schema.rb b/db/schema.rb index 23709840f..a60623de1 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20240225093946) do +ActiveRecord::Schema.define(version: 20231229020410) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/features/donations/online_donation.feature b/features/donations/online_donation.feature deleted file mode 100644 index 1918f4861..000000000 --- a/features/donations/online_donation.feature +++ /dev/null @@ -1,50 +0,0 @@ -Feature: dedicated landing page for online donations - - As a patron - So that I can support the theater's various missions - I want to easily make online donations and know what fund they're supporting - -Background: - - Given the following account codes exist: - | name | code | description | donation_prompt | - | History Fund | 7575 | The History Fund supports exhibits about the theater's history. | | - | Show Sponsorship | 8080 | Sponsorship of Altarena productions | Name of show to sponsor: | - And I am logged in as customer "Tom Foolery" - -Scenario: landing on donation page with valid account code - When I visit the donation landing page coded for fund 7575 - Then I should see "Donation to History Fund" - And I should see "exhibits about the theater's history" - When I fill in "donation" with "65" - And I press "submit" - Then I should be on the Checkout page - And I should see "Donation to History Fund" - And I should see "$65.00" - -Scenario: not filling in a donation amount should return you to donation page - When I visit the donation landing page coded for fund 7575 - And I press "submit" - Then I should see "Donation to History Fund" - -Scenario: landing on donation page with invalid account code - When I visit the donation landing page coded for a nonexistent fund - Then I should see "Donation to General Fund" - -Scenario: change donation prompt - When I login as boxoffice manager - And I change the "Donation prompt" for account code 7575 to "Donate to support our history" - And I visit the donation landing page coded for fund 7575 - Then I should see "Donate to support our history" - -@stubs_successful_credit_card_payment -Scenario: contents of donation prompt field are recorded as donation comment - When I visit the donation landing page coded for fund 8080 - Then I should see "Donation to Show Sponsorship" - When I fill in "Name of show to sponsor:" with "Guys and Dolls" - And I fill in "donation" with "999" - And I press "submit" - Then I should be on the Checkout page - And I should see "Donation to Show Sponsorship Guys and Dolls" - When I place my order with a valid credit card - Then customer "Tom Foolery" should have a donation of $999 to "Show Sponsorship" with comment "Guys and Dolls" diff --git a/features/donations/quick_donation.feature b/features/donations/quick_donation.feature index 79bb34a58..036ec406b 100644 --- a/features/donations/quick_donation.feature +++ b/features/donations/quick_donation.feature @@ -5,10 +5,15 @@ Feature: quick donation without logging in To make it easier for people to donate I want to provide a way to donate with a credit card without logging in +Background: + Given the following account codes exist: + | name | code | description | donation_prompt | + | Soda Fund | 0504 | The Soda Funds aims to put a Soda Fountain in Soda Hall | | + And I am logged in as customer "Tom Foolery" + Scenario: donor logged in, page gets prepopulated with donor info Given a donation of $10 on 2009-12-01 from "Tom Foolery" to the "General Fund" - And I am logged in as customer "Tom Foolery" When I go to the quick donation page When I fill in "Donation amount" with "15" @@ -92,3 +97,26 @@ Scenario: admin logged in, records donation on behalf of patron And customer "Joe Mallon" should have a donation of $9.00 to "General Fund" And an email should be sent to customer "Joe Mallon" containing "$ 9.00 Donation to General Fund" +Scenario: landing on quick donation page with valid account code + When I visit the quick donation landing page for account code 0504 + Then I should not see "Donate to" + And I should see "Soda Fund" + And I should see "The Soda Funds aims to put a Soda Fountain in Soda Hall Address" + +Scenario: landing on quick donation page with invalid account code + When I visit the quick donation landing page for account code 0505 + Then I should see "Invalid Fund ID" + +Scenario: landing on quick donation page with no account code + When I go to the quick donation page + Then I should not see "Donate to" + And I should see "General Fund" + And I should see "General Fund Address" + +Scenario: landing on quick donation page with valid account code and making quick donation + When I go to the quick donation page + When I fill in "Donation amount" with "15" + And I press "Charge Donation to Credit Card" + Then I should see "You have paid a total of $15.00 by Credit card" + And customer "Tom Foolery" should have a donation of $15.00 to "Soda Fund" + diff --git a/features/support/paths.rb b/features/support/paths.rb index 7a6259527..20c02ba3d 100644 --- a/features/support/paths.rb +++ b/features/support/paths.rb @@ -77,8 +77,9 @@ def path_to(page_name) date_str =~ /that performance/ edit_show_showdate_path(@showdate.show,@showdate) - when /the donation landing page coded for fund (.*)/i then donate_to_fund_path(AccountCode.find_by_code!($1)) + when /the donation landing page coded for fund (.*)/i then quick_donate_path(AccountCode.find_by_code!($1)) when /the donation landing page coded for a nonexistent fund/i then donate_to_fund_path('999999') + when /the quick donation landing page for account code (.*)/i then '/donate/' + $1.to_s + '?account_code_string=' + $1.to_s when /the edit page for the "(.*)" vouchertype/ then edit_vouchertype_path(Vouchertype.find_by_name!($1)) diff --git a/lib/tasks/create_staging_data.rake b/lib/tasks/create_staging_data.rake index 1777aad41..9ba8a99f5 100644 --- a/lib/tasks/create_staging_data.rake +++ b/lib/tasks/create_staging_data.rake @@ -20,7 +20,7 @@ module StagingHelper end def self.switch_to_staging! abort_if_production! - abort "Only a1-staging and sandbox are valid tenants" unless ['a1-staging','sandbox'].include?(StagingHelper::TENANT) + # abort "Only a1-staging and sandbox are valid tenants" unless ['a1-staging','sandbox'].include?(StagingHelper::TENANT) Apartment::Tenant.switch! StagingHelper::TENANT end end diff --git a/spec/controllers/store_controller_spec.rb b/spec/controllers/store_controller_spec.rb index d006b981c..acb9d9540 100644 --- a/spec/controllers/store_controller_spec.rb +++ b/spec/controllers/store_controller_spec.rb @@ -3,7 +3,7 @@ describe StoreController do before :each do ; @buyer = create(:customer) ; end - + shared_examples_for 'initial visit' do before :each do @r = {:controller => 'store', :action => 'index'} @@ -81,7 +81,7 @@ it_should_behave_like 'initial visit' end describe 'to :donate_to_fund' do - before :each do ; @action = :donate_to_fund ; @extras = {:id => mock_model(AccountCode)}; end + before :each do ; @action = :donate_to_fund ; @extras = { id: '2' }; end it_should_behave_like 'initial visit' end end @@ -101,6 +101,27 @@ end end + describe 'GET #donate_to_fund_redirect' do + before :each do + @new_account_code = create(:account_code, id: 2) + @anon = Customer.anonymous_customer + end + it 'redirects to donate route with fund code' do + fund_code = @new_account_code.code + get :donate_to_fund_redirect, {:id => fund_code, :customer_id => @anon} + expect(response).to redirect_to(quick_donate_path(account_code_string: fund_code)) + end + it 'sets the fund code to default code when it is missing' do + get :donate_to_fund_redirect, { :customer_id => @anon } + expect(response).to redirect_to(quick_donate_path(account_code_string: Donation.default_code.code)) + end + it 'sets the fund code to default code when it is invalid' do + invalid_fund_code = ' ' + get :donate_to_fund_redirect, { id: invalid_fund_code, :customer_id => @anon } + expect(response).to redirect_to(quick_donate_path(account_code_string: Donation.default_code.code)) + end +end + describe 'quick donation with nonexistent customer' do before :each do @new_valid_customer = attributes_for(:customer).except(:password,:password_confirmation) @@ -112,7 +133,7 @@ it 'redirects having created the customer' do post :process_donation, {:customer => @new_valid_customer, :donation => 5, :credit_card_token => 'dummy'} created_customer = Customer.find_by!(:email => @new_valid_customer[:email]) - expect(response).to redirect_to(quick_donate_path(:donation => 5, :customer_id => created_customer.id)) + expect(response).to redirect_to(quick_donate_path(:donation => 5, :customer_id => created_customer.id, :account_code_string => Donation.default_code.code)) end it 'shows error message' do post :process_donation, {:customer => @new_valid_customer, :donation => 5, :credit_card_token => 'dummy'} @@ -123,7 +144,7 @@ it 'redirects having created the customer' do post :process_donation, {:customer => @new_valid_customer, :credit_card_token => 'dummy'} created_customer = Customer.find_by!(:email => @new_valid_customer[:email]) - expect(response).to redirect_to(quick_donate_path(:donation => 0, :customer_id => created_customer.id)) + expect(response).to redirect_to(quick_donate_path(:donation => 0, :customer_id => created_customer.id, :account_code_string => Donation.default_code.code)) end it 'shows error message' do post :process_donation, :customer => @new_valid_customer, :credit_card_token => 'dummy' @@ -133,7 +154,7 @@ context 'when new customer not valid as purchaser' do before(:each) do @invalid_customer = attributes_for(:customer).except(:city,:state) - @params = {:customer => @invalid_customer, :donation => 5, :credit_card_token => 'dummy'} + @params = {:customer => @invalid_customer, :donation => 5, :credit_card_token => 'dummy', :account_code_string => Donation.default_code.code} end it 'does not create new customer' do expect { post :process_donation, @params }.not_to change { Customer.all.size } @@ -147,7 +168,7 @@ expect(flash[:alert]).to match(/Incomplete or invalid donor/i) end end - + end describe "processing empty cart" do before :each do