diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml index feab2fc9..bb8772b8 100644 --- a/.github/workflows/rspec.yml +++ b/.github/workflows/rspec.yml @@ -70,7 +70,7 @@ jobs: - name: "Create and migrate the DB" run: | bin/rails db:create - bin/rails db:migrate + bin/rails db:migrate:with_data bin/rails db:test:prepare - name: "Run Rspec" diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index 30b23651..36b2c560 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -104,6 +104,9 @@ Rails/BulkChangeTable: - 'db/migrate/20140605045004_extract_address_into_multiple_fields.rb' - 'db/migrate/20140616030905_change_camping_type_on_ticket_requests.rb' - 'db/migrate/20160611234315_add_eald_columns.rb' + - 'db/migrate/20240728211432_remove_ea_ld.rb' + - 'db/migrate/20240728223048_event_prices_as_integers.rb' + - 'db/migrate/20240729210234_ticket_requests_cleanup.rb' # Offense count: 3 # Configuration parameters: Include. @@ -157,6 +160,9 @@ Rails/ReversibleMigration: - 'db/migrate/20140605053705_remove_ask_how_many_shifts_from_events.rb' - 'db/migrate/20140605060026_add_camping_type_to_ticket_requests.rb' - 'db/migrate/20140616030905_change_camping_type_on_ticket_requests.rb' + - 'db/migrate/20240728211432_remove_ea_ld.rb' + - 'db/migrate/20240728223048_event_prices_as_integers.rb' + - 'db/migrate/20240729210234_ticket_requests_cleanup.rb' # Offense count: 3 # Configuration parameters: ForbiddenMethods, AllowedMethods. diff --git a/.version b/.version index 0495c4a8..f0bb29e7 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -1.2.3 +1.3.0 diff --git a/Gemfile b/Gemfile index 6b960ab2..aa9f3af2 100644 --- a/Gemfile +++ b/Gemfile @@ -5,7 +5,8 @@ source 'https://rubygems.org' ruby File.read('.ruby-version') # Use main development branch of Rails -gem 'rails', '=7.1.3.2' +gem 'data_migrate' +gem 'rails', '=7.1.3.4' # Unclear if we need to require it explicitly # gem 'activesupport', '=7.1.3.2' @@ -95,7 +96,7 @@ group :development, :test do gem 'rubocop-rails' gem 'rubocop-rails-omakase', require: false gem 'rubocop-rake' - gem 'rubocop-rspec' + gem 'rubocop-rspec', '~> 2.29.2' end group :development do diff --git a/Gemfile.lock b/Gemfile.lock index b2f35f80..1e6836a8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -4,35 +4,35 @@ GEM accept_values_for (0.9.3) activemodel (>= 6.1, < 8.0) rspec (>= 3.10, < 4.0) - actioncable (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + actioncable (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailbox (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.3.2) - actionpack (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionmailer (7.1.3.4) + actionpack (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activesupport (= 7.1.3.4) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.3.2) - actionview (= 7.1.3.2) - activesupport (= 7.1.3.2) + actionpack (7.1.3.4) + actionview (= 7.1.3.4) + activesupport (= 7.1.3.4) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -40,35 +40,35 @@ GEM rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.2) - actionpack (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + actiontext (7.1.3.4) + actionpack (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.2) - activesupport (= 7.1.3.2) + actionview (7.1.3.4) + activesupport (= 7.1.3.4) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.3.2) - activesupport (= 7.1.3.2) + activejob (7.1.3.4) + activesupport (= 7.1.3.4) globalid (>= 0.3.6) - activemodel (7.1.3.2) - activesupport (= 7.1.3.2) - activerecord (7.1.3.2) - activemodel (= 7.1.3.2) - activesupport (= 7.1.3.2) + activemodel (7.1.3.4) + activesupport (= 7.1.3.4) + activerecord (7.1.3.4) + activemodel (= 7.1.3.4) + activesupport (= 7.1.3.4) timeout (>= 0.4.0) - activestorage (7.1.3.2) - actionpack (= 7.1.3.2) - activejob (= 7.1.3.2) - activerecord (= 7.1.3.2) - activesupport (= 7.1.3.2) + activestorage (7.1.3.4) + actionpack (= 7.1.3.4) + activejob (= 7.1.3.4) + activerecord (= 7.1.3.4) + activesupport (= 7.1.3.4) marcel (~> 1.0) - activesupport (7.1.3.2) + activesupport (7.1.3.4) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -78,8 +78,6 @@ GEM minitest (>= 5.1) mutex_m tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) airbrussh (1.5.2) sshkit (>= 1.6.1, != 1.7.0) annotate (3.2.0) @@ -106,8 +104,8 @@ GEM msgpack (~> 1.2) brakeman (6.1.2) racc - builder (3.2.4) - capistrano (3.18.1) + builder (3.3.0) + capistrano (3.19.1) airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) @@ -127,27 +125,28 @@ GEM capistrano-slackify (2.10.3) capistrano (>= 3.2.0) multi_json - carrierwave (3.0.7) - activemodel (>= 6.0.0) - activesupport (>= 6.0.0) - addressable (~> 2.6) - image_processing (~> 1.1) - marcel (~> 1.0.0) - ssrf_filter (~> 1.0) + carrierwave (1.3.4) + activemodel (>= 4.0.0) + activesupport (>= 4.0.0) + mime-types (>= 1.16) + ssrf_filter (~> 1.0, < 1.1.0) codecov (0.2.12) json simplecov - colorize (0.8.1) - concurrent-ruby (1.3.1) + colorize (1.1.0) + concurrent-ruby (1.3.3) connection_pool (2.4.1) countries (6.0.1) unaccent (~> 0.3) country_select (9.0.0) countries (> 5.0, < 7.0) crass (1.0.6) - cssbundling-rails (1.4.0) + cssbundling-rails (1.4.1) railties (>= 6.0.0) dalli (3.2.8) + data_migrate (9.4.0) + activerecord (>= 6.1) + railties (>= 6.1) date (3.3.4) debug (1.9.2) irb (~> 1.10) @@ -160,18 +159,17 @@ GEM responders warden (~> 1.2.3) diff-lcs (1.5.1) - docile (1.4.0) + docile (1.4.1) drb (2.2.1) ed25519 (1.3.0) - erubi (1.12.0) + erubi (1.13.0) factory_bot (6.4.6) activesupport (>= 5.0.0) factory_bot_rails (6.4.3) factory_bot (~> 6.4) railties (>= 5.0.0) - faker (3.4.1) + faker (3.4.2) i18n (>= 1.8.11, < 2) - ffi (1.16.3) flatpickr (4.6.13.1) foreman (0.88.1) globalid (1.2.1) @@ -188,27 +186,24 @@ GEM hashie (5.0.0) i18n (1.14.5) concurrent-ruby (~> 1.0) - image_processing (1.12.2) - mini_magick (>= 4.9.5, < 5) - ruby-vips (>= 2.0.17, < 3) io-console (0.7.2) - irb (1.13.1) + irb (1.14.0) rdoc (>= 4.0.0) reline (>= 0.4.2) jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) - jsbundling-rails (1.3.0) + jsbundling-rails (1.3.1) railties (>= 6.0.0) json (2.7.2) language_server-protocol (3.17.0.3) - libv8-node (21.7.2.0) - libv8-node (21.7.2.0-aarch64-linux) - libv8-node (21.7.2.0-aarch64-linux-musl) - libv8-node (21.7.2.0-arm64-darwin) - libv8-node (21.7.2.0-x86_64-darwin) - libv8-node (21.7.2.0-x86_64-linux) - libv8-node (21.7.2.0-x86_64-linux-musl) + libv8-node (22.5.1.0) + libv8-node (22.5.1.0-aarch64-linux) + libv8-node (22.5.1.0-aarch64-linux-musl) + libv8-node (22.5.1.0-arm64-darwin) + libv8-node (22.5.1.0-x86_64-darwin) + libv8-node (22.5.1.0-x86_64-linux) + libv8-node (22.5.1.0-x86_64-linux-musl) lograge (0.14.0) actionpack (>= 4) activesupport (>= 4) @@ -224,15 +219,18 @@ GEM net-pop net-smtp marcel (1.0.4) - mini_magick (4.12.0) + mime-types (3.5.2) + mime-types-data (~> 3.2015) + mime-types-data (3.2024.0702) + mini_magick (5.0.1) mini_mime (1.1.5) - mini_racer (0.12.0) - libv8-node (~> 21.7.2.0) - minitest (5.23.1) + mini_racer (0.13.0) + libv8-node (~> 22.5.1.0) + minitest (5.24.1) msgpack (1.7.2) multi_json (1.15.0) mutex_m (0.2.0) - net-imap (0.4.12) + net-imap (0.4.14) date net-protocol net-pop (0.1.2) @@ -247,28 +245,28 @@ GEM net-protocol net-ssh (7.2.3) net_http_unix (0.2.2) - newrelic_rpm (9.10.0) + newrelic_rpm (9.12.0) nio4r (2.7.3) - nokogiri (1.16.5-aarch64-linux) + nokogiri (1.16.7-aarch64-linux) racc (~> 1.4) - nokogiri (1.16.5-arm-linux) + nokogiri (1.16.7-arm-linux) racc (~> 1.4) - nokogiri (1.16.5-arm64-darwin) + nokogiri (1.16.7-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.5-x86-linux) + nokogiri (1.16.7-x86-linux) racc (~> 1.4) - nokogiri (1.16.5-x86_64-darwin) + nokogiri (1.16.7-x86_64-darwin) racc (~> 1.4) - nokogiri (1.16.5-x86_64-linux) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) orm_adapter (0.5.0) - parallel (1.24.0) - paranoia (2.6.3) + parallel (1.25.1) + paranoia (2.6.4) activerecord (>= 5.1, < 7.2) - parser (3.3.2.0) + parser (3.3.4.0) ast (~> 2.4.1) racc - pg (1.5.6) + pg (1.5.7) propshaft (0.9.0) actionpack (>= 7.0.0) activesupport (>= 7.0.0) @@ -278,15 +276,13 @@ GEM activemodel (>= 5.0) psych (5.1.2) stringio - public_suffix (5.0.5) puma (6.4.2) nio4r (~> 2.0) - puma-status (1.6) - colorize (~> 0.8) + puma-status (1.7) net_http_unix (~> 0.2) parallel (~> 1) - racc (1.8.0) - rack (3.0.11) + racc (1.8.1) + rack (3.1.7) rack-session (2.0.0) rack (>= 3.0.0) rack-test (2.1.0) @@ -294,20 +290,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.1.3.2) - actioncable (= 7.1.3.2) - actionmailbox (= 7.1.3.2) - actionmailer (= 7.1.3.2) - actionpack (= 7.1.3.2) - actiontext (= 7.1.3.2) - actionview (= 7.1.3.2) - activejob (= 7.1.3.2) - activemodel (= 7.1.3.2) - activerecord (= 7.1.3.2) - activestorage (= 7.1.3.2) - activesupport (= 7.1.3.2) + rails (7.1.3.4) + actioncable (= 7.1.3.4) + actionmailbox (= 7.1.3.4) + actionmailer (= 7.1.3.4) + actionpack (= 7.1.3.4) + actiontext (= 7.1.3.4) + actionview (= 7.1.3.4) + activejob (= 7.1.3.4) + activemodel (= 7.1.3.4) + activerecord (= 7.1.3.4) + activestorage (= 7.1.3.4) + activesupport (= 7.1.3.4) bundler (>= 1.15.0) - railties (= 7.1.3.2) + railties (= 7.1.3.4) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -315,9 +311,9 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.1.3.2) - actionpack (= 7.1.3.2) - activesupport (= 7.1.3.2) + railties (7.1.3.4) + actionpack (= 7.1.3.4) + activesupport (= 7.1.3.4) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -333,23 +329,23 @@ GEM connection_pool regexp_parser (2.9.2) relaxed-rubocop (2.5) - reline (0.5.8) + reline (0.5.9) io-console (~> 0.5) request_store (1.7.0) rack (>= 1.4) responders (3.1.1) actionpack (>= 5.2) railties (>= 5.2) - rexml (3.2.8) - strscan (>= 3.0.9) - rouge (4.2.1) + rexml (3.3.2) + strscan + rouge (4.3.0) rspec (3.13.0) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) rspec-mocks (~> 3.13.0) rspec-core (3.13.0) rspec-support (~> 3.13.0) - rspec-expectations (3.13.0) + rspec-expectations (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) rspec-its (1.3.0) @@ -358,7 +354,7 @@ GEM rspec-mocks (3.13.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.13.0) - rspec-rails (6.1.2) + rspec-rails (6.1.3) actionpack (>= 6.1) activesupport (>= 6.1) railties (>= 6.1) @@ -367,30 +363,30 @@ GEM rspec-mocks (~> 3.13) rspec-support (~> 3.13) rspec-support (3.13.1) - rubocop (1.64.1) + rubocop (1.65.0) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) parser (>= 3.3.0.2) rainbow (>= 2.2.2, < 4.0) - regexp_parser (>= 1.8, < 3.0) + regexp_parser (>= 2.4, < 3.0) rexml (>= 3.2.5, < 4.0) rubocop-ast (>= 1.31.1, < 2.0) ruby-progressbar (~> 1.7) unicode-display_width (>= 2.4.0, < 3.0) rubocop-ast (1.31.3) parser (>= 3.3.1.0) - rubocop-capybara (2.20.0) - rubocop (~> 1.41) - rubocop-factory_bot (2.25.1) + rubocop-capybara (2.21.0) rubocop (~> 1.41) - rubocop-minitest (0.35.0) + rubocop-factory_bot (2.26.1) + rubocop (~> 1.61) + rubocop-minitest (0.35.1) rubocop (>= 1.61, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-performance (1.21.0) + rubocop-performance (1.21.1) rubocop (>= 1.48.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0) - rubocop-rails (2.25.0) + rubocop-rails (2.25.1) activesupport (>= 4.2.0) rack (>= 1.1) rubocop (>= 1.33.0, < 2.0) @@ -407,35 +403,32 @@ GEM rubocop-capybara (~> 2.17) rubocop-factory_bot (~> 2.22) rubocop-rspec_rails (~> 2.28) - rubocop-rspec_rails (2.28.3) - rubocop (~> 1.40) + rubocop-rspec_rails (2.29.1) + rubocop (~> 1.61) ruby-progressbar (1.13.0) - ruby-vips (2.2.1) - ffi (~> 1.12) simplecov (0.22.0) docile (~> 1.1) simplecov-html (~> 0.11) simplecov_json_formatter (~> 0.1) simplecov-html (0.12.3) simplecov_json_formatter (0.1.4) - sshkit (1.22.2) + sshkit (1.23.0) base64 - mutex_m net-scp (>= 1.1.2) net-sftp (>= 2.1.2) net-ssh (>= 2.8.0) - ssrf_filter (1.1.2) + ssrf_filter (1.0.8) stimulus-rails (1.3.3) railties (>= 6.0.0) - stringio (3.1.0) - stripe (11.6.0) + stringio (3.1.1) + stripe (11.7.0) strscan (3.1.0) temple (0.10.3) thor (1.3.1) - tilt (2.3.0) - timecop (0.9.9) + tilt (2.4.0) + timecop (0.9.10) timeout (0.4.1) - turbo-rails (2.0.5) + turbo-rails (2.0.6) actionpack (>= 6.0.0) activejob (>= 6.0.0) railties (>= 6.0.0) @@ -457,7 +450,7 @@ GEM websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) yard (0.9.36) - zeitwerk (2.6.15) + zeitwerk (2.6.17) PLATFORMS aarch64-linux @@ -493,6 +486,7 @@ DEPENDENCIES country_select cssbundling-rails dalli + data_migrate debug devise ed25519 @@ -517,7 +511,7 @@ DEPENDENCIES psych puma (>= 6) puma-status - rails (= 7.1.3.2) + rails (= 7.1.3.4) rake redis (>= 4.0.1) relaxed-rubocop @@ -527,7 +521,7 @@ DEPENDENCIES rubocop-rails rubocop-rails-omakase rubocop-rake - rubocop-rspec + rubocop-rspec (~> 2.29.2) simplecov stimulus-rails stripe (~> 11.3) diff --git a/LICENSE b/LICENSE index be37acaa..9084cee2 100644 --- a/LICENSE +++ b/LICENSE @@ -8,8 +8,8 @@ Authors include, but not limited to: - Konstantin Gredeskoul, @kigster on Github - Matt Levy, @beingmattlevy on Github - Friends and Family (FnF) Engineers -- California Foundation for The Advancement - of The Electronic Arts (CFAEA) 501(c)(3) +- The California Foundation for the Advancement + of the Electronic Arts (CFAEA) 501(c)3 LICENSE diff --git a/app/assets/images/icons/pass.png b/app/assets/images/icons/pass.png new file mode 100644 index 00000000..f2e566c3 Binary files /dev/null and b/app/assets/images/icons/pass.png differ diff --git a/app/controllers/eald_payments_controller.rb b/app/controllers/eald_payments_controller.rb deleted file mode 100644 index 507ecf4e..00000000 --- a/app/controllers/eald_payments_controller.rb +++ /dev/null @@ -1,89 +0,0 @@ -# frozen_string_literal: true - -require 'tempfile' -require 'csv' - -# Handles payments for early access/late departure passes. -class EaldPaymentsController < ApplicationController - before_action :set_event - before_action :require_event_admin, except: %i[new create complete] - - include ActionView::Helpers::NumberHelper - - def index - @eald_payments = EaldPayment.where(event_id: @event) - .order('created_at DESC') - .to_a - end - - def new - email = permitted_params.fetch(:email, '') - full_name = permitted_params.fetch(:name, '') - early_arrival_passes = permitted_params.fetch(:early_arrival_passes, 1) - late_departure_passes = permitted_params.fetch(:late_departure_passes, 1) - @eald_payment = EaldPayment.new(event_id: @event.id, - email:, - name: full_name, - early_arrival_passes:, - late_departure_passes:) - end - - def create - @eald_payment = EaldPayment.new(params[:eald_payment]) - - if @eald_payment.save_and_charge! - EaldPaymentMailer.eald_payment_received(@eald_payment).deliver_later - redirect_to complete_event_eald_payments_path(@event) - else - render action: 'new' - end - end - - def complete - render - end - - def download - temp_csv = Tempfile.new('csv') - - CSV.open(temp_csv.path, 'wb') do |csv| - csv << %w[name email transaction_id early_arrival_passes late_departure_passes timestamp] - EaldPayment.where(event_id: @event).find_each do |p| - csv << [p.name, - p.email, - p.stripe_charge_id, - p.early_arrival_passes, - p.late_departure_passes, - p.created_at.to_i] - end - end - - temp_csv.close - send_file(temp_csv.path, - filename: "#{@event.name} EALD Passes.csv", - type: 'text/csv') - end - - private - - def set_event - @event = Event.where(id: permitted_params[:event_id].to_i).first - end - - def permitted_params - params.permit( - :id, - :event_id, - :eald_payment, - :email, - :name, - :early_arrival_passes, - :late_departure_passes, - :_method, - :authenticity_token, - :commit - ) - .to_hash - .with_indifferent_access - end -end diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 25ad1f7a..e18887b2 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -24,20 +24,31 @@ def show def new @event = Event.new(Event::DEFAULT_ATTRIBUTES) + @event.build_default_event_addons end def edit params_symbolized_hash[:event]&.each_pair do |key, value| @event.send("#{key}=", value) if @event.respond_to?("#{key}=") end + + # build default event addons if event does not have persisted addons + @event.create_default_event_addons + render end def create - create_params = params_symbolized_hash[:event].dup + create_params = params_symbolized_hash[:event].dup.with_indifferent_access + Rails.logger.info("event_create: create_params: #{create_params}") TimeHelper.normalize_time_attributes(create_params) @event = Event.new(create_params) + # if create_params[:event_addons_attributes].present? + # @event.build_event_addons_from_params(create_params[:event_addons_attributes]) + # end + + Rails.logger.info("event_create: created event: #{@event.id} event_addons: #{@event.event_addons.inspect}") if @event.save redirect_to @event @@ -51,6 +62,8 @@ def update update_params = params_symbolized_hash[:event].dup TimeHelper.normalize_time_attributes(update_params) + Rails.logger.info("event_update: #{update_params}") + if @event.update(update_params) redirect_to @event, notice: 'The event has been updated.' else @@ -116,41 +129,37 @@ def params_symbolized_hash def set_event @event = Event.where(id: permitted_params[:id].to_i).first + return if @event.event_addons.present? + + @event.create_default_event_addons + Rails.logger.info("event_set: event: #{@event.id} addons.size: #{@event.event_addons.size} event_addons: #{@event.event_addons.inspect}") end def permitted_params - params.permit( - :id, - :user_email, - :user_id, - :_method, - :authenticity_token, - :commit, - event: %i[ - start_time - end_time - ticket_sales_start_time - ticket_sales_end_time - ticket_requests_end_time - adult_ticket_price - allow_donations - allow_financial_assistance - cabin_price - early_arrival_price - end_time - kid_ticket_price - late_departure_price - max_adult_tickets_per_request - max_cabin_requests - max_cabins_per_request - max_kid_tickets_per_request - name - require_mailing_address - require_role - start_time - tickets_require_approval - ] - ) + params.permit(:id, + :user_email, + :user_id, + :_method, + :authenticity_token, + :commit, + event: [ + :name, + :start_time, + :end_time, + :ticket_sales_start_time, + :ticket_sales_end_time, + :ticket_requests_end_time, + :adult_ticket_price, + :kid_ticket_price, + :max_adult_tickets_per_request, + :max_kid_tickets_per_request, + :allow_donations, + :allow_financial_assistance, + :require_mailing_address, + :require_role, + :tickets_require_approval, + { event_addons_attributes: %i[id addon_id price] } + ]) .to_hash .with_indifferent_access end diff --git a/app/controllers/ticket_requests_controller.rb b/app/controllers/ticket_requests_controller.rb index 93258f24..3ddb9de9 100644 --- a/app/controllers/ticket_requests_controller.rb +++ b/app/controllers/ticket_requests_controller.rb @@ -21,16 +21,17 @@ def index requests = @ticket_requests.select { |tr| tr.send("#{status}?") } stats[status] = { - requests: requests.count, - adults: requests.sum(&:adults), - kids: requests.sum(&:kids), - cabins: requests.sum(&:cabins), - raised: requests.sum(&:price) + requests: requests.count, + adults: requests.sum(&:adults), + kids: requests.sum(&:kids), + addon_passes: requests.sum(&:active_addon_pass_sum), + addon_camping: requests.sum(&:active_addon_camp_sum), + raised: requests.sum(&:price) } end @stats[:total] ||= Hash.new { |h, k| h[k] = 0 } - %i[requests adults kids cabins raised].each do |measure| + %i[requests adults kids addon_passes addon_camping raised].each do |measure| %i[pending awaiting_payment completed].each do |status| @stats[:total][measure] += @stats[status][measure] end @@ -73,11 +74,11 @@ def show def new @ticket_request = TicketRequest.new(event_id: @event.id) - unless @event.ticket_requests_open? return redirect_to root_path end + # load event addons if signed_in? @user = current_user @@ -86,6 +87,10 @@ def new redirect_to event_ticket_request_path(event_id: @event.id, id: existing_request.id) end end + + # build addons + @ticket_request.build_ticket_request_event_addons + @ticket_request end def edit @@ -113,13 +118,14 @@ def create return render_flash(flash) end + Rails.logger.debug { "ticket request create: tr_params: #{tr_params}" } + ticket_request_user = current_user tr_params[:user_id] = ticket_request_user.id @ticket_request = TicketRequest.new(tr_params, user_id: ticket_request_user.id, - event_id: @event.id, - guests: []) + event_id: @event.id) Rails.logger.info("Newly created request: #{@ticket_request.inspect}") @@ -132,14 +138,17 @@ def create target: @ticket_request ).fire! - if (@event.tickets_require_approval || @ticket_request.free?) && @ticket_request.total_tickets > 1 + if @event.tickets_require_approval && @ticket_request.total_tickets > 1 + Rails.logger.debug { "tr approval: #{@ticket_request.inspect}" } redirect_to event_ticket_request_path(@event, @ticket_request), notice: 'When you know your guest names, please return here and add them below.' elsif !@ticket_request.all_guests_specified? + Rails.logger.debug { "tr NOT all guests specified: #{@ticket_request.inspect}" } # XXX there is a bug here that flashes this when only 1 ticket being purchased. redirect_to edit_event_ticket_request_path(@event, @ticket_request), notice: 'Please enter the guest names before you are able to pay for the ticket.' - elsif @ticket_request.approved? + elsif !@event.tickets_require_approval || @ticket_request.approved? + Rails.logger.debug { "tr please pay: #{@ticket_request.inspect}" } redirect_to event_ticket_request_payments_path(@event, @ticket_request), notice: 'Please pay for your ticket(s).' end @@ -267,7 +276,6 @@ def permitted_params :user_id, :adults, :kids, - :cabins, :needs_assistance, :notes, :special_price, @@ -276,8 +284,6 @@ def permitted_params :donation, :role, :role_explanation, - :car_camping, - :car_camping_explanation, :previous_contribution, :address_line1, :address_line2, @@ -287,9 +293,8 @@ def permitted_params :country_code, :admin_notes, :agrees_to_terms, - :early_arrival_passes, - :late_departure_passes, - { guest_list: [] } + { guest_list: [] }, + { ticket_request_event_addons_attributes: %i[id ticket_request_id event_addon_id quantity] } ] ) .to_hash diff --git a/app/helpers/payments_helper.rb b/app/helpers/payments_helper.rb index d5c2c844..9c9c2f58 100644 --- a/app/helpers/payments_helper.rb +++ b/app/helpers/payments_helper.rb @@ -1,16 +1,7 @@ # frozen_string_literal: true module PaymentsHelper - # Calculates the extra amount to charge based off of Stripe's fees so that the - # full original amount is sent to the event organizer. - STRIPE_RATE = BigDecimal('0.029', 10) # 2.9% per transaction - STRIPE_TRANSACTION_FEE = BigDecimal('0.30', 10) # +30 cents per transaction - def extra_amount_to_charge(_original_amount) - # XXX: For now, disable passing fees on to user - # extra = (original_amount * STRIPE_RATE + STRIPE_TRANSACTION_FEE) / (1 - STRIPE_RATE) - # extra_cents = (extra * 100).ceil # Round up to the nearest cent - # BigDecimal.new(extra_cents, 10) / 100 0 end end diff --git a/app/helpers/ticket_requests_helper.rb b/app/helpers/ticket_requests_helper.rb index 2c7a0475..e30f59c9 100644 --- a/app/helpers/ticket_requests_helper.rb +++ b/app/helpers/ticket_requests_helper.rb @@ -40,23 +40,6 @@ def text_for_status(ticket_request) end end - def eald_requested?(ticket_request) - ticket_request.early_arrival_passes.positive? || - ticket_request.late_departure_passes.positive? - end - - # Not perfect, but looks up the email address associated with the request and - # checks if enough EA/LD passes have been purchased with that email address to - # meet or exceed the originally requested amount in the request. - def eald_paid?(ticket_request) - eald_payments = EaldPayment.where(event: ticket_request.event, - email: ticket_request.user.email).to_a - ea_passes = eald_payments.sum(&:early_arrival_passes) - ld_passes = eald_payments.sum(&:late_departure_passes) - ea_passes >= ticket_request.early_arrival_passes && - ld_passes >= ticket_request.late_departure_passes - end - def price_rules_to_json(event) event.price_rules.to_h do |price_rule| [price_rule.trigger_value, price_rule.price.to_i] @@ -86,16 +69,9 @@ def help_text_for(sym) # HACK: This copy is specific for TicketBooth--we'll have to add a # customization so that this can be set on a per-event basis <<-HELP - Kids 12 and under are free. They do need to be registered with name and age on the - ticket request form. Reach out to tickets@fnf.org if you have any questions. - HELP - when :cabins - <<-HELP - There are a limited number of wood and tent cabins available. - Both the cabins and the tents are the same price. We encourage everyone to - bring their own tents and camping gear so that they don't need a cabin. - Due to limited availability, we will obviously not be able to grant all - requests. + Babes in arms are free. + Kids need to be registered with name and age on the ticket request form. + Reach out to tickets@fnf.org if you have any questions. HELP when :address "We'll mail your tickets to this address." diff --git a/app/javascript/controllers/tickets_request_controller.js b/app/javascript/controllers/tickets_request_controller.js index 6a1a7768..48d19c67 100644 --- a/app/javascript/controllers/tickets_request_controller.js +++ b/app/javascript/controllers/tickets_request_controller.js @@ -44,7 +44,7 @@ export default class TicketsRequestController extends Controller { evt.preventDefault(); }); - $('#ticket_request_adults, #ticket_request_kids, #ticket_request_cabins, #ticket_request_early_arrival_passes, #ticket_request_late_departure_passes') + $('#ticket_request_adults, #ticket_request_kids') .on('change keyup mouseup', function (evt) { const numberField = $(this), priceDisplay = numberField.find('+ .inline-price'), diff --git a/app/mailers/eald_payment_mailer.rb b/app/mailers/eald_payment_mailer.rb deleted file mode 100644 index 99b4ce2e..00000000 --- a/app/mailers/eald_payment_mailer.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -class EaldPaymentMailer < ApplicationMailer - def eald_payment_received(eald_payment) - @eald_payment = eald_payment - @event = @eald_payment.event - mail to: "#{@eald_payment.name} <#{@eald_payment.email}>", - from: from_email, - reply_to: reply_to_email, - subject: "Your payment for #{@event.name} Early Arrival/Late Departure passes has been received" - end -end diff --git a/app/mailers/ticket_request_mailer.rb b/app/mailers/ticket_request_mailer.rb index e582352a..2bde4292 100644 --- a/app/mailers/ticket_request_mailer.rb +++ b/app/mailers/ticket_request_mailer.rb @@ -41,17 +41,6 @@ def request_approved(ticket_request) @payment_url = new_event_ticket_request_payment_url(@event, @ticket_request, @auth_token) - if @event.eald? - @extra_params = {}.tap do |params| - params[:early_arrival_passes] = @ticket_request.early_arrival_passes - params[:late_departure_passes] = @ticket_request.late_departure_passes - params[:email] = @ticket_request.user.email - params[:name] = @ticket_request.user.name - end - - @eald_url = new_event_eald_payment_path(@event, @extra_params) - end - # Return if the authentication token is blank return if @auth_token.blank? diff --git a/app/models/addon.rb b/app/models/addon.rb new file mode 100644 index 00000000..45598d69 --- /dev/null +++ b/app/models/addon.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: addons +# +# id :bigint not null, primary key +# category :string not null +# default_price :integer not null +# name :string not null +# created_at :datetime not null +# updated_at :datetime not null +# +class Addon < ApplicationRecord + has_many :event_addons, autosave: true, dependent: :destroy + has_many :ticket_request_event_addons, autosave: true, dependent: :destroy + + CATEGORIES = [CATEGORY_PASS = 'pass', + CATEGORY_CAMP = 'camp'].freeze + + HUMANIZED_CATEGORIES = { + CATEGORY_PASS => 'Event Passes', + CATEGORY_CAMP => 'Camping Permits' + }.freeze + + validates :category, presence: true, inclusion: { in: CATEGORIES } + validates :name, presence: true + validates :default_price, presence: true, numericality: { greater_than_or_equal_to: 0 } + + def self.categories + CATEGORIES + end + + def humanized_category + HUMANIZED_CATEGORIES[category] + end + + def self.order_by_category + order(:category, :id) + end +end diff --git a/app/models/eald_payment.rb b/app/models/eald_payment.rb deleted file mode 100644 index be8510ab..00000000 --- a/app/models/eald_payment.rb +++ /dev/null @@ -1,60 +0,0 @@ -# frozen_string_literal: true - -# == Schema Information -# -# Table name: eald_payments -# -# id :integer not null, primary key -# amount_charged_cents :integer not null -# early_arrival_passes :integer default(0), not null -# email :string(255) not null -# late_departure_passes :integer default(0), not null -# name :string(255) not null -# created_at :datetime -# updated_at :datetime -# event_id :integer -# stripe_charge_id :string not null -# -class EaldPayment < ApplicationRecord - include PaymentsHelper - - belongs_to :event - - attr_accessible :event_id, :name, :email, :early_arrival_passes, :late_departure_passes, :stripe_card_token - - validates :early_arrival_passes, - presence: true, - numericality: { only_integer: true, greater_than_or_equal_to: 0 } - - validates :late_departure_passes, - presence: true, - numericality: { only_integer: true, greater_than_or_equal_to: 0 } - - attr_accessor :stripe_card_token - - def save_and_charge! - if valid? - amount_to_charge = price + extra_amount_to_charge(price) - amount_to_charge_cents = (amount_to_charge * 100).to_i - - charge = Stripe::Charge.create( - amount: amount_to_charge_cents, - currency: 'usd', - card: stripe_card_token, - description: "#{event.name} EA/LD Pass" - ) - - self.stripe_charge_id = charge.id - self.amount_charged_cents = charge.amount - save - end - rescue Stripe::StripeError => e - errors.add :base, e.message - false - end - - def price - (early_arrival_passes * event.early_arrival_price) + - (late_departure_passes * event.late_departure_price) - end -end diff --git a/app/models/event.rb b/app/models/event.rb index 6a4ea2df..389d655b 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -4,21 +4,16 @@ # # Table name: events # -# id :integer not null, primary key -# adult_ticket_price :decimal(8, 2) +# id :bigint not null, primary key +# adult_ticket_price :integer # allow_donations :boolean default(FALSE), not null # allow_financial_assistance :boolean default(FALSE), not null -# cabin_price :decimal(8, 2) -# early_arrival_price :decimal(8, 2) default(0.0) # end_time :datetime -# kid_ticket_price :decimal(8, 2) -# late_departure_price :decimal(8, 2) default(0.0) +# kid_ticket_price :integer # max_adult_tickets_per_request :integer -# max_cabin_requests :integer -# max_cabins_per_request :integer # max_kid_tickets_per_request :integer -# name :string(255) -# photo :string(255) +# name :string +# photo :string # require_mailing_address :boolean default(FALSE), not null # require_role :boolean default(TRUE), not null # slug :text @@ -27,8 +22,8 @@ # ticket_sales_end_time :datetime # ticket_sales_start_time :datetime # tickets_require_approval :boolean default(TRUE), not null -# created_at :datetime -# updated_at :datetime +# created_at :datetime not null +# updated_at :datetime not null # class Event < ApplicationRecord has_many :event_admins @@ -37,19 +32,21 @@ class Event < ApplicationRecord has_many :time_slots, through: :jobs has_many :ticket_requests, dependent: :destroy has_many :price_rules, dependent: :destroy + has_many :event_addons, dependent: :destroy + has_many :addons, through: :event_addons MAX_NAME_LENGTH = 100 GUEST_LIST_FINAL_WITHIN = 2.days attr_accessible :name, :start_time, :end_time, :adult_ticket_price, - :early_arrival_price, :late_departure_price, - :kid_ticket_price, :cabin_price, :max_adult_tickets_per_request, - :max_kid_tickets_per_request, :max_cabins_per_request, :max_cabin_requests, + :kid_ticket_price, :max_adult_tickets_per_request, :max_kid_tickets_per_request, :photo, :photo_cache, :tickets_require_approval, :require_mailing_address, :require_role, :allow_financial_assistance, :allow_donations, :ticket_sales_start_time, :ticket_sales_end_time, - :ticket_requests_end_time + :ticket_requests_end_time, :event_addons_attributes + + accepts_nested_attributes_for :event_addons mount_uploader :photo, PhotoUploader @@ -63,13 +60,10 @@ class Event < ApplicationRecord validates :end_time, presence: true validates :adult_ticket_price, presence: true, numericality: { greater_than_or_equal_to: 0 } validates :kid_ticket_price, allow_nil: true, numericality: { greater_than_or_equal_to: 0 } - validates :cabin_price, allow_nil: true, numericality: { greater_than_or_equal_to: 0 } validates :max_adult_tickets_per_request, allow_nil: true, numericality: { only_integer: true, greater_than: 0 } validates :max_kid_tickets_per_request, allow_nil: true, numericality: { only_integer: true, greater_than: 0 } - validates :max_cabins_per_request, allow_nil: true, numericality: { only_integer: true, greater_than: 0 } - validates :max_cabin_requests, allow_nil: true, numericality: { only_integer: true, greater_than: 0 } - validate :end_time_after_start_time, :sales_end_time_after_start_time, :ensure_prices_set_if_maximum_specified + validate :end_time_after_start_time, :sales_end_time_after_start_time scope :sales_open, -> { where('ticket_sales_start_time < :now', now: Time.current) } scope :future_event, -> { where('start_time > :now', now: Time.current) } @@ -84,9 +78,7 @@ class Event < ApplicationRecord ticket_sales_end_time: START_DATE_WITH_OFFSET[7.days], adult_ticket_price: 220, - early_arrival_price: 0, - kid_ticket_price: 0, - late_departure_price: 30, + kid_ticket_price: 100, max_adult_tickets_per_request: 6, max_kid_tickets_per_request: 4, @@ -96,11 +88,7 @@ class Event < ApplicationRecord allow_donations: true, require_mailing_address: false, - require_role: true, - - max_cabins_per_request: nil, - max_cabin_requests: nil, - cabin_price: nil + require_role: true }.freeze def admissible_requests @@ -131,13 +119,6 @@ def make_admin(user) EventAdmin.create(user_id: user.id, event_id: id) end - def cabins_available? - return false unless cabin_price - return true unless max_cabin_requests - - ticket_requests.not_declined.sum(:cabins) < max_cabin_requests - end - StatusWidget = Struct.new(:name, :css_class) def status @@ -194,16 +175,82 @@ def ticket_requests_open? false end - def eald? - early_arrival_price.positive? || late_departure_price.positive? - end - def to_param return nil unless persisted? [id, slug].join('-') # 1-summer-campout-xii end + def build_event_addons_from_params(build_params) + return if build_params.blank? + + Rails.logger.debug { "build_event_addons_from_params: #{build_params}" } + + build_params.each_value do |value| + if Addon.exists?(id: value['addon_id']) + event_addons.build({ event_id: id, addon_id: value['addon_id'], price: value['price'] }) + end + end + + Rails.logger.debug { "build_event_addons_from_params: save: #{event_addons.inspect}" } + event_addons + end + + # create default event addons from Addons + def create_default_event_addons + return if event_addons.present? + + build_default_event_addons + save + Rails.logger.debug { "create_default_event_addons: save: #{event_addons.inspect}" } + event_addons + end + + def build_default_event_addons + return if event_addons.present? + + Addon.order_by_category.each do |addon| + event_addons.build({ event: self, addon: }).set_default_values + end + + Rails.logger.debug { "build_default_event_addons: #{event_addons.inspect}" } + event_addons + end + + def active_event_addons + event_addons.where('price > ?', 0) + end + + def active_event_addons? + event_addons.where('price > ?', 0).count.positive? + end + + def active_event_addons_passes? + @active_event_addons_passes ||= active_event_addons_by_category(Addon::CATEGORY_PASS).count + end + + def active_event_addons_camping? + @active_event_addons_camping ||= active_event_addons_by_category(Addon::CATEGORY_CAMP).count + end + + def active_event_addons_by_category(category) + event_addons.joins(:addon, :event) + .where(event_id: id, 'addon.category' => category) + .where('price > ?', 0) + end + + def active_sorted_event_addons + event_addons.where('price > ?', 0).sort_by { |e| [e.category, e.price, e.name] } + end + + def sorted_event_addons + event_addons.sort_by { |e| [e.category, e.id] } + end + + def passes? + active_sorted_event_addons + end + private def generate_slug! @@ -221,23 +268,6 @@ def sales_end_time_after_start_time end end - def ensure_prices_set_if_maximum_specified - if max_kid_tickets_per_request && kid_ticket_price.blank? - errors.add(:max_kid_tickets_per_request, - 'can be set only if a kid ticket price is set') - end - - if max_cabins_per_request && cabin_price.blank? - errors.add(:max_cabins_per_request, - 'can be set only if a cabin price is set') - end - - if max_cabin_requests && cabin_price.blank? - errors.add(:max_cabin_requests, - 'can be set only if a cabin price is set') - end - end - def ensure_require_role_set_default attributes[:require_role] = true if attributes[:require_role].nil? end diff --git a/app/models/event_addon.rb b/app/models/event_addon.rb new file mode 100644 index 00000000..3eb60d5c --- /dev/null +++ b/app/models/event_addon.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: event_addons +# +# id :bigint not null, primary key +# price :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# addon_id :bigint not null +# event_id :bigint not null +# +# Indexes +# +# index_event_addons_on_addon_id (addon_id) +# index_event_addons_on_event_id (event_id) +# +# Foreign Keys +# +# fk_rails_... (addon_id => addons.id) +# fk_rails_... (event_id => events.id) +# +class EventAddon < ApplicationRecord + belongs_to :addon + belongs_to :event + attr_accessible :id, :event_id, :addon_id, :price, :event, :addon + + before_validation :set_default_values + + validates :price, presence: true, numericality: { greater_than_or_equal_to: 0 } + + delegate :name, to: :addon + delegate :category, to: :addon + delegate :humanized_category, to: :addon + + def set_default_values + self.price ||= addon.default_price + end + + def category_and_name + "#{humanized_category}: #{name} ($)" + end +end diff --git a/app/models/event_admin.rb b/app/models/event_admin.rb index 75ba8ab1..4cef97f4 100644 --- a/app/models/event_admin.rb +++ b/app/models/event_admin.rb @@ -4,11 +4,11 @@ # # Table name: event_admins # -# id :integer not null, primary key -# created_at :datetime -# updated_at :datetime -# event_id :integer -# user_id :integer +# id :bigint not null, primary key +# created_at :datetime not null +# updated_at :datetime not null +# event_id :bigint +# user_id :bigint # # Indexes # diff --git a/app/models/job.rb b/app/models/job.rb index 5386e08a..26f3557f 100644 --- a/app/models/job.rb +++ b/app/models/job.rb @@ -4,12 +4,16 @@ # # Table name: jobs # -# id :integer not null, primary key +# id :bigint not null, primary key # description :string(512) not null # name :string(100) not null -# created_at :datetime -# updated_at :datetime -# event_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# event_id :bigint not null +# +# Indexes +# +# index_jobs_on_event_id (event_id) # class Job < ApplicationRecord belongs_to :event diff --git a/app/models/payment.rb b/app/models/payment.rb index d188ab78..ae801078 100644 --- a/app/models/payment.rb +++ b/app/models/payment.rb @@ -4,11 +4,11 @@ # # Table name: payments # -# id :integer not null, primary key -# explanation :string(255) +# id :bigint not null, primary key +# explanation :string # status :string(1) default("N"), not null -# created_at :datetime -# updated_at :datetime +# created_at :datetime not null +# updated_at :datetime not null # stripe_charge_id :string(255) # stripe_payment_id :string # stripe_refund_id :string @@ -146,7 +146,7 @@ def retrieve_payment_intent # check if we have the same cost if payment_intent.amount != (amount = calculate_cost) self.payment_intent = update_payment_intent_amount(amount) - Rails.logger.debug { "retrieve_payment_intent updated payment intent with new amount [#{amount}] => #{payment_intent}}" } + Rails.logger.info { "retrieve_payment_intent updated payment intent with new amount [#{amount}] => #{payment_intent}}" } end Rails.logger.debug { "retrieve_payment_intent payment => #{inspect}}" } diff --git a/app/models/price_rule.rb b/app/models/price_rule.rb index 8dbf7229..f5ba5445 100644 --- a/app/models/price_rule.rb +++ b/app/models/price_rule.rb @@ -4,13 +4,13 @@ # # Table name: price_rules # -# id :integer not null, primary key +# id :bigint not null, primary key # price :decimal(8, 2) # trigger_value :integer -# type :string(255) -# created_at :datetime -# updated_at :datetime -# event_id :integer +# type :string +# created_at :datetime not null +# updated_at :datetime not null +# event_id :bigint # # Indexes # diff --git a/app/models/price_rule/kids_equal_to.rb b/app/models/price_rule/kids_equal_to.rb index d24df0f1..ba9306b4 100644 --- a/app/models/price_rule/kids_equal_to.rb +++ b/app/models/price_rule/kids_equal_to.rb @@ -4,13 +4,13 @@ # # Table name: price_rules # -# id :integer not null, primary key +# id :bigint not null, primary key # price :decimal(8, 2) # trigger_value :integer -# type :string(255) -# created_at :datetime -# updated_at :datetime -# event_id :integer +# type :string +# created_at :datetime not null +# updated_at :datetime not null +# event_id :bigint # # Indexes # diff --git a/app/models/shift.rb b/app/models/shift.rb index 0d6677b4..867e45e4 100644 --- a/app/models/shift.rb +++ b/app/models/shift.rb @@ -4,12 +4,17 @@ # # Table name: shifts # -# id :integer not null, primary key +# id :bigint not null, primary key # name :string(70) -# created_at :datetime -# updated_at :datetime -# time_slot_id :integer not null -# user_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# time_slot_id :bigint not null +# user_id :bigint not null +# +# Indexes +# +# index_shifts_on_time_slot_id (time_slot_id) +# index_shifts_on_user_id (user_id) # class Shift < ApplicationRecord belongs_to :time_slot diff --git a/app/models/site_admin.rb b/app/models/site_admin.rb index a083383d..186995d2 100644 --- a/app/models/site_admin.rb +++ b/app/models/site_admin.rb @@ -4,9 +4,9 @@ # # Table name: site_admins # -# id :integer not null, primary key -# created_at :datetime -# updated_at :datetime +# id :bigint not null, primary key +# created_at :datetime not null +# updated_at :datetime not null # user_id :integer not null # class SiteAdmin < ApplicationRecord diff --git a/app/models/ticket_request.rb b/app/models/ticket_request.rb index 0ba702a4..15c5fce7 100644 --- a/app/models/ticket_request.rb +++ b/app/models/ticket_request.rb @@ -4,36 +4,31 @@ # # Table name: ticket_requests # -# id :integer not null, primary key -# address_line1 :string(200) -# address_line2 :string(200) -# admin_notes :string(512) -# adults :integer default(1), not null -# agrees_to_terms :boolean -# cabins :integer default(0), not null -# car_camping :boolean -# car_camping_explanation :string(200) -# city :string(50) -# country_code :string(4) -# deleted_at :datetime -# donation :decimal(8, 2) default(0.0) -# early_arrival_passes :integer default(0), not null -# guests :text -# kids :integer default(0), not null -# late_departure_passes :integer default(0), not null -# needs_assistance :boolean default(FALSE), not null -# notes :string(500) -# previous_contribution :string(250) -# role :string(255) default("volunteer"), not null -# role_explanation :string(200) -# special_price :decimal(8, 2) -# state :string(50) -# status :string(1) not null -# zip_code :string(32) -# created_at :datetime -# updated_at :datetime -# event_id :integer not null -# user_id :integer not null +# id :bigint not null, primary key +# address_line1 :string(200) +# address_line2 :string(200) +# admin_notes :string(512) +# adults :integer default(1), not null +# agrees_to_terms :boolean +# city :string(50) +# country_code :string(4) +# deleted_at :datetime +# donation :decimal(8, 2) default(0.0) +# guests :text +# kids :integer default(0), not null +# needs_assistance :boolean default(FALSE), not null +# notes :string(500) +# previous_contribution :string(250) +# role :string default("volunteer"), not null +# role_explanation :string(200) +# special_price :decimal(8, 2) +# state :string(50) +# status :string(1) not null +# zip_code :string(32) +# created_at :datetime not null +# updated_at :datetime not null +# event_id :integer not null +# user_id :integer not null # # Indexes # @@ -75,7 +70,6 @@ def csv_columns id adults kids - cabins needs_assistance notes status @@ -95,10 +89,6 @@ def csv_columns zip_code country_code admin_notes - car_camping - car_camping_explanation - early_arrival_passes - late_departure_passes guests ] end @@ -136,7 +126,7 @@ def csv_columns ROLES = { ROLE_UBER_COORDINATOR => 'Skipper/Board Member', - ROLE_COORDINATOR => 'Lead Coordinator', + ROLE_COORDINATOR => 'Coordinator', ROLE_CONTRIBUTOR => 'Planner', ROLE_VOLUNTEER => 'Volunteer', ROLE_OTHER => 'Other (Art Grantee, a DJ, etc)' @@ -147,21 +137,24 @@ def csv_columns has_one :payment, inverse_of: :ticket_request + has_many :ticket_request_event_addons, dependent: :destroy + has_many :event_addons, through: :ticket_request_event_addons + # Serialize guest emails as an array in a text field. serialize :guests, coder: Psych, type: Array - attr_accessible :user_id, :adults, :kids, :cabins, :needs_assistance, + attr_accessible :user_id, :adults, :kids, :needs_assistance, :notes, :status, :special_price, :event_id, - :user_attributes, :user, :donation, :role, :role_explanation, - :car_camping, :car_camping_explanation, :previous_contribution, + :user_attributes, :user, :donation, :role, + :role_explanation, :previous_contribution, :address_line1, :address_line2, :city, :state, :zip_code, :country_code, :admin_notes, :agrees_to_terms, - :early_arrival_passes, :late_departure_passes, :guests + :guests, :ticket_request_event_addons_attributes - normalize_attributes :notes, :role_explanation, :previous_contribution, - :admin_notes, :car_camping_explanation + normalize_attributes :notes, :role_explanation, :previous_contribution, :admin_notes accepts_nested_attributes_for :user + accepts_nested_attributes_for :ticket_request_event_addons before_validation :set_defaults @@ -170,10 +163,7 @@ def csv_columns validates :status, presence: true, inclusion: { in: STATUSES } validates :address_line1, :city, :state, :zip_code, :country_code, presence: { if: -> { event.try(:require_mailing_address) } } validates :adults, presence: true, numericality: { only_integer: true, greater_than: 0 } - validates :early_arrival_passes, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } - validates :late_departure_passes, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } validates :kids, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } - validates :cabins, allow_nil: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } validates :role, presence: true, inclusion: { in: ROLES.keys } validates :role_explanation, presence: { if: -> { role == ROLE_OTHER } }, length: { maximum: 400 } validates :previous_contribution, length: { maximum: 250 } @@ -276,22 +266,30 @@ def refund end end + # calculate the total price for this ticket request def price return special_price if special_price + total = tickets_price + total += calculate_addons_price + total + end + + def tickets_price total = adults * event.adult_ticket_price + total += (kids * event.kid_ticket_price) if event.kid_ticket_price.present? + total + end - if event.kid_ticket_price - custom_price = event.price_rules.map do |price_rule| - price_rule.calc_price(self) - end.compact.min + def calculate_addons_price + return 0 unless ticket_request_event_addons? - total += custom_price || (kids * event.kid_ticket_price) + tr_addons_price = 0 + ticket_request_event_addons.each do |tr_event_addon| + tr_addons_price += tr_event_addon.calculate_cost end - total += cabins * event.cabin_price if event.cabin_price - - total + tr_addons_price end def cost @@ -329,6 +327,60 @@ def country_name ISO3166::Country[country_code] end + def build_ticket_request_event_addons + return if event.blank? || ticket_request_event_addons.present? + + event.active_event_addons.each do |event_addon| + ticket_request_event_addons.build(event_addon:).set_default_values + end + + Rails.logger.debug { "build_ticket_request_event_addons: #{ticket_request_event_addons.inspect}" } + ticket_request_event_addons + end + + def build_ticket_request_event_addons_from_params(build_params) + return if build_params.blank? + + Rails.logger.debug { "build_ticket_request_event_addons_from_params: #{build_params}" } + + build_params.each_value do |value| + if EventAddon.exists?(id: value['event_addon_id']) + ticket_request_event_addons.build({ ticket_request_id: id, event_addon_id: value['event_addon_id'], quantity: value['quantity'] }) + end + end + + Rails.logger.debug { "build_ticket_request_event_addons_from_params: save: #{event_addons.ticket_request_event_addons}" } + ticket_request_event_addons + end + + def active_addons + ticket_request_event_addons.where('quantity > ?', 0) + end + + def active_addons_sum + active_addons.sum(&:quantity) + end + + def active_sorted_addons + active_addons.sort_by { |e| [e.category, e.price, e.name] } + end + + def active_addon_pass_sum + active_addon_sum_quantity_by_category(Addon::CATEGORY_PASS) + end + + def active_addon_camp_sum + active_addon_sum_quantity_by_category(Addon::CATEGORY_CAMP) + end + + def active_addon_sum_quantity_by_category(category) + active_addons.select { |addon| addon.category == category }.sum(&:quantity) + end + + def ticket_request_event_addons? + active_addons.count.positive? + end + def set_defaults self.status = nil if status.blank? self.status ||= if event diff --git a/app/models/ticket_request_event_addon.rb b/app/models/ticket_request_event_addon.rb new file mode 100644 index 00000000..1fcaee00 --- /dev/null +++ b/app/models/ticket_request_event_addon.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: ticket_request_event_addons +# +# id :bigint not null, primary key +# quantity :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# event_addon_id :bigint not null +# ticket_request_id :bigint not null +# +# Indexes +# +# index_ticket_request_event_addons_on_event_addon_id (event_addon_id) +# index_ticket_request_event_addons_on_ticket_request_id (ticket_request_id) +# +# Foreign Keys +# +# fk_rails_... (event_addon_id => event_addons.id) +# fk_rails_... (ticket_request_id => ticket_requests.id) +# +class TicketRequestEventAddon < ApplicationRecord + belongs_to :event_addon + belongs_to :ticket_request + + attr_accessible :id, :event_addon_id, :ticket_request_id, :quantity, :event_addon, :ticket_request + + PURCHASE_CATEGORIES = { + Addon::CATEGORY_PASS => 'Passes', + Addon::CATEGORY_CAMP => 'Permits' + }.freeze + + validates :quantity, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 } + + delegate :name, to: :event_addon + delegate :price, to: :event_addon + delegate :category, to: :event_addon + delegate :humanized_category, to: :event_addon + + def set_default_values + self.quantity ||= 0 + end + + def calculate_cost + price * quantity + end + + def purchase_category(category) + PURCHASE_CATEGORIES[category] + end + + def name_category_price_each + "#{name} #{purchase_category(category)} @ #{price} each" + end +end diff --git a/app/models/time_slot.rb b/app/models/time_slot.rb index d039b600..a1b22068 100644 --- a/app/models/time_slot.rb +++ b/app/models/time_slot.rb @@ -4,13 +4,17 @@ # # Table name: time_slots # -# id :integer not null, primary key +# id :bigint not null, primary key # end_time :datetime not null # slots :integer not null # start_time :datetime not null -# created_at :datetime -# updated_at :datetime -# job_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# job_id :bigint not null +# +# Indexes +# +# index_time_slots_on_job_id (job_id) # class TimeSlot < ApplicationRecord belongs_to :job diff --git a/app/models/user.rb b/app/models/user.rb index 3bd3c3b6..6d5d64ac 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -4,30 +4,30 @@ # # Table name: users # -# id :integer not null, primary key +# id :bigint not null, primary key # authentication_token :string(64) # confirmation_sent_at :datetime -# confirmation_token :string(255) +# confirmation_token :string # confirmed_at :datetime # current_sign_in_at :datetime -# current_sign_in_ip :string(255) -# email :string(255) not null -# encrypted_password :string(255) not null +# current_sign_in_ip :string +# email :string not null +# encrypted_password :string not null # failed_attempts :integer default(0) # first :text # last :text # last_sign_in_at :datetime -# last_sign_in_ip :string(255) +# last_sign_in_ip :string # locked_at :datetime # name :string(70) not null # remember_created_at :datetime # reset_password_sent_at :datetime -# reset_password_token :string(255) +# reset_password_token :string # sign_in_count :integer default(0) -# unconfirmed_email :string(255) -# unlock_token :string(255) -# created_at :datetime -# updated_at :datetime +# unconfirmed_email :string +# unlock_token :string +# created_at :datetime not null +# updated_at :datetime not null # # Indexes # diff --git a/app/views/devise/registrations/_change_password.html.haml b/app/views/devise/registrations/_change_password.html.haml index 1244b4d2..482e1f2d 100644 --- a/app/views/devise/registrations/_change_password.html.haml +++ b/app/views/devise/registrations/_change_password.html.haml @@ -4,7 +4,8 @@ - if existing %small.nowrap NOTE: leave these fields blank if you don't want to change your password. - else - %h5 Please enter your new password, twice for confirmation. + %h5 Please enter and confirm your new password. + NOTE: Passwords must be at least 6 characters long. .row .col-5 diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index 57936fae..6bb3f63f 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -1,5 +1,3 @@ .card - .card-header.bg-dark-subtle - %h2 Register a New Account .card-body = render partial: 'form', locals: { existing: resource&.id.nil? ? false : true, resource: resource, resource_name: resource_name} diff --git a/app/views/devise/shared/_links.html.haml b/app/views/devise/shared/_links.html.haml index e0bf57ea..576ba8cf 100644 --- a/app/views/devise/shared/_links.html.haml +++ b/app/views/devise/shared/_links.html.haml @@ -1,4 +1,8 @@ -%button.btn.btn-secondary.btn-md.rounded{"aria-controls" => "resetLinks", "aria-expanded" => "false", "data-bs-target" => "#resetLinks", "data-bs-toggle" => "collapse", :type => "button"} Account Reset, Unlock & Restore +%button.btn.btn-secondary.btn-md.rounded{"aria-controls" => "resetLinks", + "aria-expanded" => "false", + "data-bs-target" => "#resetLinks", + "data-bs-toggle" => "collapse", + :type => "button"} Forgot Password / Account Help #resetLinks.collapse.multi-collapse .card.card-body.small.bg-body-secondary %ul.shared-user-links diff --git a/app/views/devise/shared/_register.html.haml b/app/views/devise/shared/_register.html.haml index f2e3ec86..c34f7a79 100644 --- a/app/views/devise/shared/_register.html.haml +++ b/app/views/devise/shared/_register.html.haml @@ -1,4 +1,4 @@ -%h2 Register +%h2 Register New Account - http_method = existing ? :put : :post = form_for(resource, as: resource_name, url: user_registration_path, html: { method: http_method }, data: { turbo: false } ) do |f| @@ -49,5 +49,7 @@ .col-12 .actions.btn-group-md = f.submit "Register", class: 'btn btn-primary btn-lg' - = link_to "Go Back ↩".html_safe, :back, class: 'btn btn-warning btn-md' + - if controller_name != 'ticket_requests' + = link_to "Go Back ↩".html_safe, :back, class: 'btn btn-warning btn-md' + %p= link_to "Forgot your password?", new_password_path(resource_name) diff --git a/app/views/eald_payment_mailer/eald_payment_received.html.haml b/app/views/eald_payment_mailer/eald_payment_received.html.haml deleted file mode 100644 index 5bd4ca8f..00000000 --- a/app/views/eald_payment_mailer/eald_payment_received.html.haml +++ /dev/null @@ -1,26 +0,0 @@ -%p - Hi #{@eald_payment.name}, - -%p - Your payment of - %b= number_to_currency(@eald_payment.amount_charged_cents.to_f / 100) - for - %b= @eald_payment.early_arrival_passes - early arrival passes and - %b= @eald_payment.late_departure_passes - late departure passes for - %b= @event.name - was received. Thank you! - -%p - Reminder: there are no refunds for Early Arrival/Late Departure passes! - -%p - Early arrival passes can be picked up at the gate when you arrive. - -%p - Late departure passes can be picked up at the Main Lodge on Sunday 12PM-4PM. - -%p - More information can be found at: - = link_to 'Early Arrival / Late Departure Policy', 'https://fnf.page.link/eald-policy' diff --git a/app/views/eald_payments/_form.html.haml b/app/views/eald_payments/_form.html.haml deleted file mode 100644 index d2fb419d..00000000 --- a/app/views/eald_payments/_form.html.haml +++ /dev/null @@ -1,77 +0,0 @@ -= form_for @eald_payment, - url: { controller: :eald_payments, action: :create } do |f| - = render 'shared/form_errors', resource: @eald_payment - - = f.hidden_field :event_id, value: @event.id - = f.hidden_field :stripe_card_token, id: 'stripe_card_token' # Value set by JS - - = f.label :name, 'Full Name', class: 'required-label' - = f.text_field :name, class: 'input-xlarge', - maxlength: User::MAX_NAME_LENGTH, required: true, - placeholder: 'First and last name' - - = f.label :email, 'Email', class: 'required-label' - = f.email_field :email, class: 'input-xlarge', - maxlength: User::MAX_EMAIL_LENGTH, required: true, - placeholder: 'email@example.com' - - = f.label :early_arrival_passes, 'Early arrival passes' - = f.number_field :early_arrival_passes, class: 'input-mini', min: 0, required: true, - data: { default_price: @event.early_arrival_price } - %span.help-inline.inline-price - - = f.label :late_departure_passes, 'Late departure passes' - = f.number_field :late_departure_passes, class: 'input-mini', min: 0, required: true, - data: { default_price: @event.late_departure_price } - %span.help-inline.inline-price - - .field - = label_tag :card_number, 'Credit Card Number' - = text_field_tag :card_number, nil, name: nil, maxlength: 16, class: 'input-large' - %span.help-inline - - %w[visa mastercard american_express discover jcb].each do |company| - = image_tag "credit-cards/#{company}_32.png" - - .field - = label_tag :card_code, 'Card Verification Code' - = text_field_tag :card_code, nil, name: nil, class: 'input-mini', maxlength: 6, - placeholder: 'NNN' - - .field - = label_tag :card_month, 'Expiration Date' - = select_month nil, { add_month_numbers: true }, - { name: nil, id: 'card_month', class: 'input-medium' } - = select_year nil, { start_year: Date.today.year, end_year: Date.today.year + 15 }, - { name: nil, id: 'card_year', class: 'input-small' } - - %hr - - %p - - extra = extra_amount_to_charge(@eald_payment.price) - Clicking "Pay Now" will charge - %strong.text-success#eald_total_price{ data: { price: @eald_payment.price } } - = number_to_currency(@eald_payment.price) - - if extra > 0 - + - %strong.text-success#eald_fee - = number_to_currency(extra) - processing fee - to the card entered above. - = tooltip_box 'This fee covers the the fees charged by our credit card processor, Stripe.' - - %p - Early Arrival / Late Departure passes are - %b NOT REFUNDABLE - - %p - More information can be found at: - = link_to 'Early Arrival / Late Departure Policy', - 'https://fnf.page.link/eald-policy' - - .actions - = f.submit 'Pay Now', class: 'btn btn-primary btn-large' - - %span.text-error#stripe-error - %noscript - JavaScript is not enabled and is required for this form. Enable it in - your web browser settings and refresh the page to continue. diff --git a/app/views/eald_payments/complete.html.haml b/app/views/eald_payments/complete.html.haml deleted file mode 100644 index c5042c61..00000000 --- a/app/views/eald_payments/complete.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -%p.lead Thanks for purchasing your Early Arrival / Late Departure pass! - -You should receive a confirmation email soon. diff --git a/app/views/eald_payments/index.html.haml b/app/views/eald_payments/index.html.haml deleted file mode 100644 index d6034973..00000000 --- a/app/views/eald_payments/index.html.haml +++ /dev/null @@ -1,26 +0,0 @@ -= render partial: 'shared/nav_event', locals: { event: @event, active_tab: { eald_passes: 'active' } } - -.card - .card-header.bg-primary-subtle - .btn-groupp.mx-4 - = link_to download_event_eald_payments_path(@event), class: 'btn btn-warning ', title: 'Download CSV of the EALD Passes' do - %i.icon-th-list - Download CSV â–¼ - - .card-body - %table.table - %thead - %tr - %th Name - %th Email - %th Transaction ID - %th Early Arrival Passes - %th Late Departure Passes - %tbody - - @eald_payments.each do |payment| - %tr - %td= payment.name - %td= payment.email - %td= payment.stripe_charge_id - %td= payment.early_arrival_passes - %td= payment.late_departure_passes diff --git a/app/views/eald_payments/new.html.haml b/app/views/eald_payments/new.html.haml deleted file mode 100644 index 04d7f787..00000000 --- a/app/views/eald_payments/new.html.haml +++ /dev/null @@ -1,29 +0,0 @@ -- content_for(:meta) do - %meta{ name: 'stripe-key', content: Rails.application.credentials.send(Rails.env.to_sym).stripe.publishable_api_key} - -- content_for(:head) do - = javascript_include_tag 'https://js.stripe.com/v3/' - -%h1 - Early Arrival / Late Departure Passes - -%p.lead - Arriving before noon on Friday or leaving after 2PM on Sunday? - -%p - Then you'll need an early arrival / late departure pass for each person in your vehicle/camp. - -%p - Have questions? Feel free to send - = link_to 'EA/LD', 'mailto:ealdfnf@gmail.com' - a message! - -%hr - -- if (@event.start_time - Time.now) < 2.5.days - Early Arrival / Late Departure purchases are closed this close to the event -- elsif (@event.start_time.beginning_of_day - Time.now) < 18.days - = render 'form' -- else - %p.lead - Early Arrival / Late Departure passes will be available for purchase closer to the campout date diff --git a/app/views/events/_event_summary.html.haml b/app/views/events/_event_summary.html.haml index a435e655..7368676f 100644 --- a/app/views/events/_event_summary.html.haml +++ b/app/views/events/_event_summary.html.haml @@ -28,29 +28,33 @@ %tr %td{colspan: 2} %hr + %h4 Ticket and Event Addon Prices %tr - %td.text-start Adult Ticket Price + %td.text-start Adult Ticket %td.px-2 %span.price = number_to_currency(@event.adult_ticket_price) - if @event.max_adult_tickets_per_request %span.muted (Maximum #{@event.max_adult_tickets_per_request} tickets) - %tr - %td.text-start Kid Ticket Price - %td.px-2 - - if @event.price_rules.any? - %ul - - @event.price_rules.order(:created_at).each do |price_rule| - %li= price_rule.rule_text - %li - Otherwise: - = number_to_currency(@event.kid_ticket_price) - - - else + - if @event.kid_ticket_price.present? + %tr + %td.text-start Kids Ticket + %td.px-2 %span.price = number_to_currency(@event.kid_ticket_price) - - - if @event.max_kid_tickets_per_request&.positive? + - if @event.max_kid_tickets_per_request.present? + %span.muted (Maximum #{@event.max_adult_tickets_per_request} tickets) + - else %span.muted - (Maximum #{@event.max_kid_tickets_per_request} kid tickets) + (Unlimited tickets) + + - if @event.active_event_addons? + %span.muted + - @event.active_sorted_event_addons.each do |event_addon| + %tr + %td.text-start + = event_addon.name + %td.px-2 + %span.price + = number_to_currency(event_addon.price) diff --git a/app/views/events/_form.html.haml b/app/views/events/_form.html.haml index fda6ce0c..56f0d5cf 100644 --- a/app/views/events/_form.html.haml +++ b/app/views/events/_form.html.haml @@ -9,31 +9,36 @@ = f.text_field :name, class: 'event-name', required: true, maxlength: Event::MAX_NAME_LENGTH = f.label :start_time, 'Start Time' - = render partial: 'shared/datetime_field', locals: {form: f, name: "start_time", datetime: (@event.start_time || 1.day.from_now.beginning_of_day) } + = render partial: 'shared/datetime_field', + locals: {form: f, name: "start_time", datetime: (@event.start_time || 1.day.from_now.beginning_of_day) } = f.label :end_time, 'End Time' - = render partial: 'shared/datetime_field', locals: {form: f, name: "end_time", datetime: (@event.end_time || 1.day.from_now.beginning_of_day)} + = render partial: 'shared/datetime_field', + locals: {form: f, name: "end_time", datetime: (@event.end_time || 1.day.from_now.beginning_of_day)} .vertical-20 %fieldset - %legend Ticket Details + %legend Ticket Sale Details = f.label :ticket_sales_start_time do Ticket Sales Opening Time %p.muted Leave blank to begin selling tickets right away - = render partial: 'shared/datetime_field', locals: {form: f, name: "ticket_sales_start_time", datetime: (@event.ticket_sales_start_time) } + = render partial: 'shared/datetime_field', + locals: {form: f, name: "ticket_sales_start_time", datetime: (@event.ticket_sales_start_time) } = f.label :ticket_sales_end_time do Ticket Sales Closing Time %p.muted Leave blank to allow selling tickets up to the end of the event - = render partial: 'shared/datetime_field', locals: {form: f, name: "ticket_sales_end_time", datetime: (@event.ticket_sales_end_time) } + = render partial: 'shared/datetime_field', + locals: {form: f, name: "ticket_sales_end_time", datetime: (@event.ticket_sales_end_time) } = f.label :ticket_requests_end_time do Ticket Requests Closing Time %p.muted Leave blank to allow requesting tickets up to the end of the event - = render partial: 'shared/datetime_field', locals: {form: f, name: "ticket_requests_end_time", datetime: (@event.ticket_requests_end_time) } + = render partial: 'shared/datetime_field', + locals: {form: f, name: "ticket_requests_end_time", datetime: (@event.ticket_requests_end_time) } %legend Event Configuration %fieldset @@ -75,53 +80,33 @@ .col-sm-12.col-md-6.col-lg-6 - %legend Event Pricing + %legend Ticket Pricing = f.label :adult_ticket_price, 'Adult Ticket Price ($)' - = f.number_field :adult_ticket_price, class: 'input-small', required: true, - min: 0 + = f.number_field :adult_ticket_price, class: 'input-small', required: true, min: 0 = f.label :max_adult_tickets_per_request do Maximum number of adult tickets allowed per ticket request? %p.muted Leave blank for no limit = f.number_field :max_adult_tickets_per_request, class: 'input-mini', min: 1 - = f.label :early_arrival_price, 'Early Arrival Price($)' - = f.number_field :early_arrival_price, class: 'input-small', required: true, - min: 0 - - = f.label :late_departure_price, 'Late Departure Price($)' - = f.number_field :late_departure_price, class: 'input-small', required: true, - min: 0 - = f.label :kid_ticket_price do Kid Ticket Price ($) - %p.muted Keep blank if you want to sell only adult tickets + %p.muted Set blank if you want to sell only adult tickets = f.number_field :kid_ticket_price, class: 'input-small', min: 0 = f.label :max_kid_tickets_per_request do Maximum number of kid tickets allowed per ticket request? - %p.muted Leave blank for no limit - = f.number_field :max_kid_tickets_per_request, class: 'input-mini', min: 1 - - = f.label :max_cabin_requests do - Maximum number of cabins that can be requested in total - %p.muted - Once more than this number of cabins is requested, subsequent ticket - requesters will not have the option to request cabins. You'll probably - want to set this value to be a little bit higher than the actual number - of cabins at your site, and then manually email the few individuals who - requested a cabin but won't get one. Leave blank for no limit (probably - not a good idea). - = f.number_field :max_cabin_requests, class: 'input-mini', min: 1 - - = f.label :cabin_price do - Cabin Price ($) - %p.muted Keep blank if there are no cabins or you aren't charging separately for them - = f.number_field :cabin_price, class: 'input-small', min: 0 - - = f.label :max_cabins_per_request do - Maximum number of cabins allowed per ticket request? - %p.muted Leave blank for no limit - = f.number_field :max_cabins_per_request, class: 'input-mini', min: 1 + %p.muted Set blank for no limit + = f.number_field :max_kid_tickets_per_request, class: 'input-mini', min: 0 + + %legend Event Addons and Pricing + %p.muted + To remove an addon from being sold at an event, set the price to 0. + + - @event.sorted_event_addons.each do |event_addon| + = f.fields_for :event_addons, event_addon do |event_addon_form| + = event_addon_form.hidden_field :addon_id, value: event_addon.addon_id + = event_addon_form.label :name, "#{event_addon.category_and_name}" + = event_addon_form.number_field :price, class: 'input-small', min: 0 = f.submit " ▶︎ Update Event", class: 'btn btn-primary btn-large' diff --git a/app/views/payment_mailer/payment_received.html.haml b/app/views/payment_mailer/payment_received.html.haml index 3b7ddc10..c161aeb5 100644 --- a/app/views/payment_mailer/payment_received.html.haml +++ b/app/views/payment_mailer/payment_received.html.haml @@ -1,19 +1,5 @@ = render partial: "payments/payment", locals: { payment: @payment } -- if @event.eald? - %p - %b Planning to arrive early or leave late? - %br - :ruby - extra_params = {} - extra_params[:early_arrival_passes] = @ticket_request.early_arrival_passes - extra_params[:late_departure_passes] = @ticket_request.late_departure_passes - extra_params[:email] = @ticket_request.user.email - extra_params[:name] = @ticket_request.user.name - = link_to 'Early Arrival / Late Departure Passes', - new_event_eald_payment_url(@event, extra_params) - must be purchased separately! - %p Got ticket questions or think something is wrong with your order? We are still here for you, drop us a line at diff --git a/app/views/payments/_payment.html.haml b/app/views/payments/_payment.html.haml index 6843a80c..be188ec5 100644 --- a/app/views/payments/_payment.html.haml +++ b/app/views/payments/_payment.html.haml @@ -7,15 +7,20 @@ %p Thanks for purchasing your tickets for #{ticket_request.event.name}! %strong - %p Adults Tickets: - = ticket_request.adults + %p Adults Tickets: #{ticket_request.adults} - %p Kids Tickets: - = ticket_request.kids + %strong + - if ticket_request.kids.present? + %p Kids Tickets: #{ticket_request.kids} + + %strong + - if ticket_request.ticket_request_event_addons? + - ticket_request.active_sorted_addons.each do |tr_event_addon| + %p #{tr_event_addon.humanized_category}: #{tr_event_addon.quantity} - #{tr_event_addon.name} %hr - %p Amount: %strong + %p Amount: = number_to_currency(payment.dollar_cost) - if ticket_request.donation > 0 (including #{number_to_currency(ticket_request.donation)} donation) diff --git a/app/views/payments/show.html.haml b/app/views/payments/show.html.haml index a0d33af1..7c5e249d 100644 --- a/app/views/payments/show.html.haml +++ b/app/views/payments/show.html.haml @@ -1,20 +1,5 @@ = render partial: "payment", locals: { payment: @payment } -- if @event.eald? - %p - %b Planning to arrive early or leave late? - %br - :ruby - extra_params = {} - extra_params[:early_arrival_passes] = @ticket_request.early_arrival_passes - extra_params[:late_departure_passes] = @ticket_request.late_departure_passes - extra_params[:email] = @ticket_request.user.email - extra_params[:name] = @ticket_request.user.name - = link_to 'Early Arrival / Late Departure Passes', - new_event_eald_payment_path(@event, extra_params), - target: '_blank' - must be purchased separately! - %p You can = link_to 'review your ticket information', diff --git a/app/views/shared/_nav_event.html.haml b/app/views/shared/_nav_event.html.haml index 909483a9..c18097dc 100644 --- a/app/views/shared/_nav_event.html.haml +++ b/app/views/shared/_nav_event.html.haml @@ -1,39 +1 @@ --# - active_tab ||= {} --# --# -# TODO: when we allow uploading images for the events, we can show it. --# -# = image_tag image_path('logos/fnf-transparent.png'), class: 'float-end event-preview' --# .card.event-nav --# .card-header.bg-dark-subtle --# .card-img-top --# %h3.d-inline-block.align-baseline --# = event.name --# %h5.d-inline-block.px-xl-5.px-lg-3.p-md-0.p-sm-0.m-0 --# = event.starting --# --# .card-body.event-nav --# .btn-group --# - if current_user.site_admin? || current_user.manages_event?(event) --# = link_to event_path(event), class: "btn #{active_tab[:event_show]}" do --# - if active_tab[:event_show] != "active" --# %i.icon-arrow-left ← --# = event.name --# - else --# = event.name --# = link_to edit_event_path(event), class: "btn #{active_tab[:event_edit]}" do --# Edit Event --# %i.icon-edit --# --# --# = link_to event_ticket_requests_path(event), class: "btn #{active_tab[:ticket_requests]}" do --# Ticket Requests --# %i.icon-inbox --# = link_to event_eald_payments_path(event), class: "btn #{active_tab[:eald_passes]}" do --# EA/LD Passes --# %i.icon-inbox --# = link_to guest_list_event_path(event), class: "btn #{active_tab[:guest_list]}" do --# Guest List --# %i.icon-th-list --# --# .vertical-20 - = render partial: 'shared/nav_event_tabs', locals: { active_tab: active_tab, event: event } diff --git a/app/views/shared/_nav_event_tabs.html.haml b/app/views/shared/_nav_event_tabs.html.haml index 3bed4afc..1e6e482d 100644 --- a/app/views/shared/_nav_event_tabs.html.haml +++ b/app/views/shared/_nav_event_tabs.html.haml @@ -31,10 +31,15 @@ = link_to event_ticket_requests_path(event), class: "nav-link #{active_tab[:ticket_requests]}" do Ticket Requests - - if event.eald? - %li.nav-item - = link_to event_eald_payments_path(event), class: "nav-link #{active_tab[:eald_passes]}" do - EA/LD Passes + -# XXX Re-enable me when ready + -# %li.nav-item + -# = link_to event_ticket_requests_path(event), class: "nav-link #{active_tab[:passes]}" do + -# Event Passes + + -# %li.nav-item + -# = link_to event_ticket_requests_path(event), class: "nav-link #{active_tab[:passes]}" do + -# Camping Permits + %li.nav-item = link_to guest_list_event_path(event), class: "nav-link #{active_tab[:guest_list]}" do diff --git a/app/views/ticket_request_mailer/request_approved.html.haml b/app/views/ticket_request_mailer/request_approved.html.haml index d4882e4e..3f8c64bc 100644 --- a/app/views/ticket_request_mailer/request_approved.html.haml +++ b/app/views/ticket_request_mailer/request_approved.html.haml @@ -15,14 +15,6 @@ purchase your = 'ticket'.pluralize(@ticket_request.total_tickets) --# XXX will re-enable once EALD has been added back --# - if @event.eald? --# %p --# %b Planning to arrive early or leave late? --# %br --# = link_to 'Early Arrival / Late Departure Passes', @eald_url --# must be purchased separately! - %p Thanks, %br diff --git a/app/views/ticket_requests/_event_role.html.haml b/app/views/ticket_requests/_event_role.html.haml index 1a53f76f..11a412ea 100644 --- a/app/views/ticket_requests/_event_role.html.haml +++ b/app/views/ticket_requests/_event_role.html.haml @@ -1,4 +1,4 @@ -%h4 How are you contributing to the event? +%h5 How are you contributing to the event? .content-fluid .row .col-lg-6.col-xl-6.col-md-12.col-sm-12 diff --git a/app/views/ticket_requests/_form.html.haml b/app/views/ticket_requests/_form.html.haml index b8b56d32..141071ab 100644 --- a/app/views/ticket_requests/_form.html.haml +++ b/app/views/ticket_requests/_form.html.haml @@ -86,33 +86,18 @@ = f.hidden_field :guests, value: @user.name_and_email - if !@ticket_request.post_payment? || (@event.admin?(current_user) && is_update) - %hr - - if @event.require_role - = render partial: 'event_role', locals: { form: f } - - - if signed_in? && @event.admin?(current_user) && is_update - .well - = f.label :special_price, 'Total Special Price ($)' - - %p.text-error - Editable by event admins only. Leave blank to use default price. - = f.number_field :special_price, class: 'input-small', min: 0 - - = f.label :adults, 'Number of adult tickets' + " @ $#{@event.adult_ticket_price.to_i} each" + %h5 Tickets + = f.label :adults, 'Number of Adult Tickets' + " @ $#{@event.adult_ticket_price.to_i} each" = f.number_field :adults, class: 'input-mini', min: 1, required: true, max: @event.max_adult_tickets_per_request, data: { default_price: @event.adult_ticket_price.to_i } - %br - - if @event.kid_ticket_price.present? %table.w-100.m-0.p-0 %tbody.m-0.p-0 %tr.align-middle %td.w-90.m-0.p-0.text-start - = f.label :kids do - Number of children (12 and under) you are bringing with you - (not transferable to adults; babes in arms are free) + = f.label :kids, 'Number of Kids (13 and under) Tickets' + " @ $#{@event.kid_ticket_price.to_i} each" = f.number_field :kids, class: 'input-mini', min: 0, max: @event.max_kid_tickets_per_request, data: { default_price: @event.kid_ticket_price.to_i, @@ -129,6 +114,27 @@ Once you submit this ticket request, and it's approved, you'll receive an email stating so. You can also bookmark this URL and return to it at a later date. In order to pay for the ticket(s) you are required to fill out the list of guests (if any) and kids (if any) you are bringing and/or inviting. + %hr + %h5 Event Addons + - @ticket_request.ticket_request_event_addons.each do |tr_event_addon| + = f.fields_for :ticket_request_event_addons, tr_event_addon do |tr_event_addon_form| + = tr_event_addon_form.hidden_field :ticket_request_event_addon_id, value: tr_event_addon.id + = tr_event_addon_form.hidden_field :event_addon_id, value: tr_event_addon.event_addon_id + = tr_event_addon_form.label :name, "Number of #{tr_event_addon.name_category_price_each}" + = tr_event_addon_form.number_field :quantity, class: 'input-small', min: 0 + + %hr + - if @event.require_role + = render partial: 'event_role', locals: { form: f } + + - if signed_in? && @event.admin?(current_user) && is_update + .well + = f.label :special_price, 'Total Special Price ($)' + + %p.text-error + Editable by event admins only. Leave blank to use default price. + = f.number_field :special_price, class: 'input-small', min: 0 + .col-lg-6.col-xl-6.col-md-12.col-sm-12 .control-group @@ -143,7 +149,6 @@ %td.text-end = tooltip_box help_text_for(:needs_assistance), title: "Financial Assistance" - .control-group - if @event.allow_donations @@ -154,7 +159,7 @@ = f.label :donation, 'Your Optional Donation:' = f.number_field :donation, class: 'input-mini', min: 0, required: false %td.text-end - = tooltip_box "Your option donation to The California Foundation for The Advancement of Electronic Arts, a 501(c)(3) nonprofit organization, is greatly appreciated and is tax deductible!" + = tooltip_box "Your option donation to The California Foundation for the Advancement of the Electronic Arts, a 501(c)3 nonprofit organization, is greatly appreciated and is tax deductible!" .control-group diff --git a/app/views/ticket_requests/_table_ticket_request_statuses.html.haml b/app/views/ticket_requests/_table_ticket_request_statuses.html.haml index d73f229e..c9c9de8e 100644 --- a/app/views/ticket_requests/_table_ticket_request_statuses.html.haml +++ b/app/views/ticket_requests/_table_ticket_request_statuses.html.haml @@ -21,8 +21,12 @@ %th.bg-dark-subtle.text-end Tickets - if event.kid_ticket_price %th.bg-dark-subtle.text-end Kids - - if event.cabin_price - %th.bg-dark-subtle.text-end Cabins + - if event.active_event_addons_passes? + %th.bg-dark-subtle.text-end + =Addon::HUMANIZED_CATEGORIES[Addon::CATEGORY_PASS] + - if event.active_event_addons_camping? + %th.bg-dark-subtle.text-end + =Addon::HUMANIZED_CATEGORIES[Addon::CATEGORY_CAMP] %th.bg-dark-subtle.text-end Earn %tbody.border-2.border-dark-subtle @@ -37,9 +41,12 @@ - if event.kid_ticket_price %td.text-end.bg-success-subtle %span= stats[:completed][:kids] - - if event.cabin_price + - if event.active_event_addons_passes? %td.text-end.bg-success-subtle - %span= stats[:completed][:cabins] + %span= stats[:completed][:addon_passes] + - if event.active_event_addons_camping? + %td.text-end.bg-success-subtle + %span= stats[:completed][:addon_camping] %td.text-end.bg-success-subtle %span = number_to_currency(stats[:completed][:raised], precision: 0) @@ -51,8 +58,10 @@ %td.text-end.bg-warning= stats[:pending][:adults] - if event.kid_ticket_price %td.text-end.bg-warning= stats[:pending][:kids] - - if event.cabin_price - %td.text-end.bg-warning= stats[:pending][:cabins] + - if event.active_event_addons_passes? + %td.text-end.bg-warning= stats[:pending][:addon_passes] + - if event.active_event_addons_camping? + %td.text-end.bg-warning= stats[:pending][:addon_camping] %td.text-end.bg-warning.fs-6 = number_to_currency(stats[:pending][:raised], precision: 0) @@ -63,8 +72,10 @@ %td.text-end.bg-warning-subtle= stats[:awaiting_payment][:adults] - if event.kid_ticket_price %td.text-end.bg-warning-subtle= stats[:awaiting_payment][:kids] - - if event.cabin_price - %td.text-end.bg-warning-subtle= stats[:awaiting_payment][:cabins] + - if event.active_event_addons_passes? + %td.text-end.bg-warning-subtle= stats[:awaiting_payment][:addon_passes] + - if event.active_event_addons_camping? + %td.text-end.bg-warning-subtle= stats[:awaiting_payment][:addon_camping] %td.text-end.bg-warning-subtle.fs-6 = number_to_currency(stats[:awaiting_payment][:raised], precision: 0) @@ -76,6 +87,8 @@ %td.bg-dark-subtle.text-end= stats[:total][:adults] - if event.kid_ticket_price %td.bg-dark-subtle.text-end= stats[:total][:kids] - - if event.cabin_price - %td.bg-dark-subtle.text-end= stats[:total][:cabins] + - if event.active_event_addons_passes? + %td.bg-dark-subtle.text-end= stats[:total][:addon_passes] + - if event.active_event_addons_camping? + %td.bg-dark-subtle.text-end= stats[:total][:addon_camping] %td.bg-dark-subtle.text-end.fs-5= number_to_currency(stats[:total][:raised], precision: 0) diff --git a/app/views/ticket_requests/_table_ticket_requests.html.haml b/app/views/ticket_requests/_table_ticket_requests.html.haml index 12e5fc6e..17904965 100644 --- a/app/views/ticket_requests/_table_ticket_requests.html.haml +++ b/app/views/ticket_requests/_table_ticket_requests.html.haml @@ -13,10 +13,8 @@ %th.bg-dark-subtle.text-end.optional-medium Tickets - if event.kid_ticket_price %th.bg-dark-subtle.text-end.optional-medium Kids - - if event.cabin_price - %th.bg-dark-subtle.text-end.optional-medium Cabins - - if event.eald? - %th.bg-dark-subtle.text-end.optional-medium EA/LD + - if event.active_event_addons? + %th.bg-dark-subtle.text-end.optional-medium Addons %th.bg-dark-subtle.text-end Total %th.bg-dark-subtle.text-end.optional-medium Date Requested %th.bg-dark-subtle.text-center Status @@ -43,9 +41,12 @@ - if ticket_request.needs_assistance = tooltip_box('Financial Assistance was requested.') do = image_tag('icons/dollar.png', width: 20, class: 'hover-tooltip') - - if ticket_request.car_camping - = tooltip_box(ticket_request.car_camping_explanation, title: "Car/RV Request:") do + - if ticket_request.active_addon_camp_sum + = tooltip_box(ticket_request.active_addon_camp_sum, title: "Camping:") do = image_tag('icons/car.png', width: 20, class: 'hover-tooltip') + - if ticket_request.active_addon_pass_sum + = tooltip_box(ticket_request.active_addon_pass_sum, title: "Passes:") do + = image_tag('icons/pass.png', width: 20, class: 'hover-tooltip') - if ticket_request.admin_notes.present? = tooltip_box(ticket_request.admin_notes, title: "Admin Notes") do = image_tag('icons/comments-admin.png', width: 20, class: 'hover-tooltip') @@ -55,20 +56,9 @@ - if event.kid_ticket_price %td.align-content-center.text-end.optional-medium= ticket_request.kids - - if event.cabin_price - %td.align-content-center.text-end.optional-medium= ticket_request.cabins - - - if event.eald? - %td.align-content-center.text-end.optional-medium - #{ticket_request.early_arrival_passes} / #{ticket_request.late_departure_passes} - -# %br - -# - if eald_requested?(ticket_request) - -# - if eald_paid?(ticket_request) - -# ✔︎ EALD Paid - -# - else - -# ✘ Not All EALD Bought - -# - else - -# ✘ Not Requested + - if event.active_event_addons? + %td.align-content-center.text-end.optional-medium= ticket_request.active_addons_sum + %td.align-content-center.text-end %span{ class: ('label label-info' if ticket_request.special_price) } = number_to_currency(ticket_request.price, precision: 0) diff --git a/app/views/ticket_requests/_ticket_request_show.html.haml b/app/views/ticket_requests/_ticket_request_show.html.haml index 9efab8fa..a021e5b3 100644 --- a/app/views/ticket_requests/_ticket_request_show.html.haml +++ b/app/views/ticket_requests/_ticket_request_show.html.haml @@ -3,37 +3,24 @@ %td.text-end.small.p-2.px-4.text-nowrap= "Name" %td %strong= ticket_request.user.name - - %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Date Requested:" - %td - %strong= ticket_request.created_at.localtime.to_formatted_s(:friendly) - %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Status:" + %td.text-end.small.p-2.px-4.text-nowrap= "Email:" %td %strong - %span.p-2.rounded{ class: text_class_for_status(ticket_request) } - = ticket_request.status_name + = mail_to ticket_request.user.email %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Total Tickets Price:" + %td.text-end.small.p-2.px-4.text-nowrap= "Date Requested:" %td - %strong - %span{ class: ('label label-info' if ticket_request.special_price) } - = number_to_currency(ticket_request.price, precision: 0) + %strong= ticket_request.created_at.localtime.to_formatted_s(:friendly) - - if ticket_request.donation&.positive? - %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Extra Donation:" - %td - %strong - = number_to_currency(ticket_request.donation, precision: 0) + - if event.tickets_require_approval %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Total Amount:" + %td.text-end.small.p-2.px-4.text-nowrap= "Status:" %td %strong - = number_to_currency(ticket_request.cost, precision: 0) + %span.p-2.rounded{ class: text_class_for_status(ticket_request) } + = ticket_request.status_name %tr %td.text-end.small.p-2.px-4.text-nowrap= "Payment:" @@ -52,7 +39,7 @@ - else - if ticket_request.all_guests_specified? - if ticket_request.awaiting_payment? - = link_to 'Pay Now', new_event_ticket_request_payment_path(event, ticket_request), class: 'btn btn-primary m-0' + = link_to 'Buy Tickets', new_event_ticket_request_payment_path(event, ticket_request), class: 'btn btn-primary m-0' - else = "Waiting on ticket approval" - else @@ -68,35 +55,11 @@ = 'ticket'.pluralize(ticket_request.total_tickets) %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Email:" + %td.text-end.small.p-2.px-4.text-nowrap= "Total Price:" %td %strong - = mail_to ticket_request.user.email - - - if event.require_mailing_address - %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Mailing Address:" - %td - %strong - %address - = ticket_request.address_line1 - - if ticket_request.address_line2.present? - %br - = ticket_request.address_line2 - %br - #{ticket_request.city}, #{ticket_request.state}, #{ticket_request.zip_code} - %br - = ticket_request.country_name - - - if event.require_role - %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Role:" - %td - %strong - = TicketRequest::ROLES[ticket_request.role] - - if ticket_request.role_explanation.present? - %blockquote= ticket_request.role_explanation - + %span{ class: ('label label-info' if ticket_request.special_price) } + = number_to_currency(ticket_request.price, precision: 0) %tr %td.text-end.small.p-2.px-4.text-nowrap= "Adult Tickets:" @@ -104,7 +67,6 @@ %strong = ticket_request.adults - - if event.kid_ticket_price %tr %td.text-end.small.p-2.px-4.text-nowrap= "Kid Tickets:" @@ -112,27 +74,50 @@ %strong = ticket_request.kids - - if event.cabin_price + - if ticket_request.ticket_request_event_addons? + - ticket_request.active_sorted_addons.each do |tr_event_addon| + %tr + %td.text-end.small.p-2.px-4.text-nowrap + = tr_event_addon.humanized_category + ':' + %td + %strong + = "#{tr_event_addon.quantity} - #{tr_event_addon.name}" + + - if ticket_request.donation&.positive? %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Cabins:" + %td.text-end.small.p-2.px-4.text-nowrap= "Extra Donation:" %td - %strong Cabins: - = ticket_request.cabins - - - if ticket_request.previous_contribution.present? + %strong + = number_to_currency(ticket_request.donation, precision: 0) %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Contribution(s) last year:" + %td.text-end.small.p-2.px-4.text-nowrap= "Total Amount:" %td %strong - = ticket_request.previous_contribution + = number_to_currency(ticket_request.cost, precision: 0) + - if event.require_mailing_address + %tr + %td.text-end.small.p-2.px-4.text-nowrap= "Mailing Address:" + %td + %strong + %address + = ticket_request.address_line1 + - if ticket_request.address_line2.present? + %br + = ticket_request.address_line2 + %br + #{ticket_request.city}, #{ticket_request.state}, #{ticket_request.zip_code} + %br + = ticket_request.country_name - - if ticket_request.car_camping + - if event.require_role %tr - %td.text-end.small.p-2.px-4.text-nowrap= "Car Camping Requested because:" + %td.text-end.small.p-2.px-4.text-nowrap= "Role:" %td %strong - = ticket_request.car_camping_explanation + = TicketRequest::ROLES[ticket_request.role] + - if ticket_request.role_explanation.present? + %blockquote= ticket_request.role_explanation - if ticket_request.needs_assistance %tr @@ -174,22 +159,3 @@ %h4 Ticket Coordinator Notes: %p.small = ticket_request.admin_notes - - - if payment && event.eald? - %tr - %td.text-end.small.p-2.px-4.text-nowrap - Planning to arrive early - %br - or leave late? - %td - :ruby - extra_params = {} - extra_params[:early_arrival_passes] = ticket_request.early_arrival_passes - extra_params[:late_departure_passes] = ticket_request.late_departure_passes - extra_params[:email] = ticket_request.user.email - extra_params[:name] = ticket_request.user.name - = link_to 'Early Arrival / Late Departure Passes', - new_event_eald_payment_path(event, extra_params), - class: 'small', - target: '_blank' - must be purchased separately! diff --git a/app/views/ticket_requests/new.html.haml b/app/views/ticket_requests/new.html.haml index 723156ed..e478a2ae 100644 --- a/app/views/ticket_requests/new.html.haml +++ b/app/views/ticket_requests/new.html.haml @@ -18,12 +18,13 @@ = link_to 'sign in', new_user_session_path to your account to review the details - .card-footer.bg-warning-subtle.p-2 - %p - %strong - Please fill out the form to request tickets. - %br - If your request is approved, you'll receive an email with further instructions. + - if @event.tickets_require_approval + .card-footer.bg-warning-subtle.p-2 + %p + %strong + Please fill out the form to request tickets. + %br + If your request is approved, you'll receive an email with further instructions. - if @event.ticket_requests_open? diff --git a/config/deploy.rb b/config/deploy.rb index 7f64278e..b577bede 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -50,7 +50,7 @@ before :starting, 'deploy:setup' namespace(:assets) do - before :precompile, 'deploy:migrate' + before :precompile, 'deploy:migrate:with_data' before :precompile, 'node:install' before :precompile, 'node:yarn:install' diff --git a/config/routes.rb b/config/routes.rb index 25e91640..cbf1e0be 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,19 +14,6 @@ devise_for :users - # WTF was this for? --@kig - # - # event_id = 9 - # - # get('fnf-tickets', controller: :ticket_requests, action: :new, event_id:) - # get('fnf_tickets', controller: :ticket_requests, action: :new, event_id:) - # get('fnftickets', controller: :ticket_requests, action: :new, event_id:) - # get('fnf', controller: :ticket_requests, action: :new, event_id:) - # get('FNF', controller: :ticket_requests, action: :new, event_id:) - # get('FnF', controller: :ticket_requests, action: :new, event_id:) - # - # get('eald', controller: :eald_payments, action: :new, event_id:) - resources :emails, only: :index resources :events do @@ -73,13 +60,6 @@ end end end - - resources :eald_payments, only: %i[index new create] do - collection do - get :complete - get :download - end - end end resources :passwords, only: [] do diff --git a/db/data/20240730034256_default_addons.rb b/db/data/20240730034256_default_addons.rb new file mode 100644 index 00000000..7bff8da2 --- /dev/null +++ b/db/data/20240730034256_default_addons.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class DefaultAddons < ActiveRecord::Migration[7.1] + def up + Addon.create category: Addon::CATEGORY_PASS, name: 'Early Arrival', default_price: 0 + Addon.create category: Addon::CATEGORY_PASS, name: 'Late Departure', default_price: 30 + Addon.create category: Addon::CATEGORY_CAMP, name: 'Car Camping', default_price: 50 + Addon.create category: Addon::CATEGORY_CAMP, name: 'RV under 20ft', default_price: 100 + Addon.create category: Addon::CATEGORY_CAMP, name: 'RV under 25ft', default_price: 125 + Addon.create category: Addon::CATEGORY_CAMP, name: 'RV over 25ft', default_price: 150 + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/data_schema.rb b/db/data_schema.rb new file mode 100644 index 00000000..db9a9c2b --- /dev/null +++ b/db/data_schema.rb @@ -0,0 +1 @@ +DataMigrate::Data.define(version: 20240730034256) diff --git a/db/migrate/20240718224717_addons.rb b/db/migrate/20240718224717_addons.rb new file mode 100644 index 00000000..add35b49 --- /dev/null +++ b/db/migrate/20240718224717_addons.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +class Addons < ActiveRecord::Migration[7.1] + def change + create_table :addons do |t| + t.string :category, null: false + t.string :name, null: false + t.integer :default_price, null: false + t.timestamps + end + + create_table :event_addons do |t| + t.references :event, index: true, foreign_key: true, null: false + t.references :addon, index: true, foreign_key: true, null: false + t.integer :price, null: false + t.timestamps + end + + create_table :ticket_request_event_addons do |t| + t.references :ticket_request, index: true, foreign_key: true, null: false + t.references :event_addon, index: true, foreign_key: true, null: false + t.integer :quantity, null: false + t.timestamps + end + end +end diff --git a/db/migrate/20240728211432_remove_ea_ld.rb b/db/migrate/20240728211432_remove_ea_ld.rb new file mode 100644 index 00000000..72caa26e --- /dev/null +++ b/db/migrate/20240728211432_remove_ea_ld.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class RemoveEaLd < ActiveRecord::Migration[7.1] + def change + remove_column :events, :early_arrival_price + remove_column :events, :late_departure_price + remove_column :events, :cabin_price + remove_column :events, :max_cabin_requests + remove_column :events, :max_cabins_per_request + + drop_table :eald_payments + end +end diff --git a/db/migrate/20240728223048_event_prices_as_integers.rb b/db/migrate/20240728223048_event_prices_as_integers.rb new file mode 100644 index 00000000..e3ec7dd1 --- /dev/null +++ b/db/migrate/20240728223048_event_prices_as_integers.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +class EventPricesAsIntegers < ActiveRecord::Migration[7.1] + def change + change_column :events, :adult_ticket_price, :integer + change_column :events, :kid_ticket_price, :integer + end +end diff --git a/db/migrate/20240729210234_ticket_requests_cleanup.rb b/db/migrate/20240729210234_ticket_requests_cleanup.rb new file mode 100644 index 00000000..94880cdf --- /dev/null +++ b/db/migrate/20240729210234_ticket_requests_cleanup.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class TicketRequestsCleanup < ActiveRecord::Migration[7.1] + def change + remove_column :ticket_requests, :cabins + remove_column :ticket_requests, :car_camping + remove_column :ticket_requests, :car_camping_explanation + remove_column :ticket_requests, :early_arrival_passes + remove_column :ticket_requests, :late_departure_passes + end +end diff --git a/db/schema.rb b/db/schema.rb deleted file mode 100644 index e3f6caaf..00000000 --- a/db/schema.rb +++ /dev/null @@ -1,178 +0,0 @@ -# This file is auto-generated from the current state of the database. Instead -# of editing this file, please use the migrations feature of Active Record to -# incrementally modify your database, and then regenerate this schema definition. -# -# This file is the source Rails uses to define your schema when running `bin/rails -# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to -# be faster and is potentially less error prone than running all of your -# migrations from scratch. Old migrations may fail to apply correctly if those -# migrations use external dependencies or application code. -# -# It's strongly recommended that you check this file into your version control system. - -ActiveRecord::Schema[7.1].define(version: 2024_03_11_182346) do - # These are extensions that must be enabled in order to support this database - enable_extension "plpgsql" - - create_table "eald_payments", force: :cascade do |t| - t.bigint "event_id" - t.string "stripe_charge_id", null: false - t.integer "amount_charged_cents", null: false - t.string "name", limit: 255, null: false - t.string "email", limit: 255, null: false - t.integer "early_arrival_passes", default: 0, null: false - t.integer "late_departure_passes", default: 0, null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["event_id"], name: "index_eald_payments_on_event_id" - end - - create_table "event_admins", force: :cascade do |t| - t.bigint "event_id" - t.bigint "user_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["event_id", "user_id"], name: "index_event_admins_on_event_id_and_user_id", unique: true - t.index ["user_id"], name: "index_event_admins_on_user_id" - end - - create_table "events", force: :cascade do |t| - t.string "name" - t.datetime "start_time", precision: nil - t.datetime "end_time", precision: nil - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.decimal "adult_ticket_price", precision: 8, scale: 2 - t.decimal "kid_ticket_price", precision: 8, scale: 2 - t.decimal "cabin_price", precision: 8, scale: 2 - t.integer "max_adult_tickets_per_request" - t.integer "max_kid_tickets_per_request" - t.integer "max_cabins_per_request" - t.integer "max_cabin_requests" - t.string "photo" - t.boolean "tickets_require_approval", default: true, null: false - t.boolean "require_mailing_address", default: false, null: false - t.boolean "allow_financial_assistance", default: false, null: false - t.boolean "allow_donations", default: false, null: false - t.datetime "ticket_sales_start_time", precision: nil - t.datetime "ticket_sales_end_time", precision: nil - t.datetime "ticket_requests_end_time", precision: nil - t.decimal "early_arrival_price", precision: 8, scale: 2, default: "0.0" - t.decimal "late_departure_price", precision: 8, scale: 2, default: "0.0" - end - - create_table "jobs", force: :cascade do |t| - t.bigint "event_id", null: false - t.string "name", limit: 100, null: false - t.string "description", limit: 512, null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["event_id"], name: "index_jobs_on_event_id" - end - - create_table "payments", force: :cascade do |t| - t.integer "ticket_request_id", null: false - t.string "stripe_charge_id", limit: 255 - t.string "stripe_charge_id", limit: 255 - t.string "status", limit: 1, default: "P", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "explanation" - end - - create_table "price_rules", force: :cascade do |t| - t.string "type" - t.bigint "event_id" - t.decimal "price", precision: 8, scale: 2 - t.integer "trigger_value" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["event_id"], name: "index_price_rules_on_event_id" - end - - create_table "shifts", force: :cascade do |t| - t.bigint "time_slot_id", null: false - t.bigint "user_id", null: false - t.string "name", limit: 70 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["time_slot_id"], name: "index_shifts_on_time_slot_id" - t.index ["user_id"], name: "index_shifts_on_user_id" - end - - create_table "site_admins", force: :cascade do |t| - t.integer "user_id", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - end - - create_table "ticket_requests", force: :cascade do |t| - t.integer "adults", default: 1, null: false - t.integer "kids", default: 0, null: false - t.integer "cabins", default: 0, null: false - t.boolean "needs_assistance", default: false, null: false - t.string "notes", limit: 500 - t.string "status", limit: 1, null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "user_id", null: false - t.decimal "special_price", precision: 8, scale: 2 - t.integer "event_id", null: false - t.decimal "donation", precision: 8, scale: 2, default: "0.0" - t.string "role", default: "volunteer", null: false - t.string "role_explanation", limit: 200 - t.string "previous_contribution", limit: 250 - t.string "address_line1", limit: 200 - t.string "address_line2", limit: 200 - t.string "city", limit: 50 - t.string "state", limit: 50 - t.string "zip_code", limit: 32 - t.string "country_code", limit: 4 - t.string "admin_notes", limit: 512 - t.boolean "car_camping" - t.string "car_camping_explanation", limit: 200 - t.boolean "agrees_to_terms" - t.integer "early_arrival_passes", default: 0, null: false - t.integer "late_departure_passes", default: 0, null: false - t.text "guests" - end - - create_table "time_slots", force: :cascade do |t| - t.bigint "job_id", null: false - t.datetime "start_time", precision: nil, null: false - t.datetime "end_time", precision: nil, null: false - t.integer "slots", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["job_id"], name: "index_time_slots_on_job_id" - end - - create_table "users", force: :cascade do |t| - t.string "email", null: false - t.string "encrypted_password", null: false - t.string "reset_password_token" - t.datetime "reset_password_sent_at", precision: nil - t.datetime "remember_created_at", precision: nil - t.integer "sign_in_count", default: 0 - t.datetime "current_sign_in_at", precision: nil - t.datetime "last_sign_in_at", precision: nil - t.string "current_sign_in_ip" - t.string "last_sign_in_ip" - t.string "confirmation_token" - t.datetime "confirmed_at", precision: nil - t.datetime "confirmation_sent_at", precision: nil - t.string "unconfirmed_email" - t.integer "failed_attempts", default: 0 - t.string "unlock_token" - t.datetime "locked_at", precision: nil - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "name", limit: 70, null: false - t.string "authentication_token", limit: 64 - t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true - t.index ["email"], name: "index_users_on_email", unique: true - t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true - t.index ["unlock_token"], name: "index_users_on_unlock_token", unique: true - end - -end diff --git a/db/seeds.rb b/db/seeds.rb index 96d5c968..464a6bbf 100755 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -46,6 +46,7 @@ def run create_site_admins create_users create_events + create_addons self.ran = true end @@ -134,15 +135,10 @@ def create_events adult_ticket_price: Faker::Commerce.price(range: 100...200), allow_donations: true, allow_financial_assistance: true, - cabin_price: Faker::Commerce.price(range: 150..300), - early_arrival_price: 25.00, end_time: start_time + 3.days, require_mailing_address: true, kid_ticket_price: Faker::Commerce.price(range: 50...100), - late_departure_price: Faker::Commerce.price(range: 15...25), max_adult_tickets_per_request: 4, - max_cabin_requests: 2, - max_cabins_per_request: 1, max_kid_tickets_per_request: 4, start_time:, venue: Faker::Address.street_address, @@ -164,6 +160,19 @@ def create_events end end + def create_addons + return if Addon.count.positive? + + puts 'Creating Addons' + Addon.create category: Addon::CATEGORY_PASS, name: 'Early Arrival', default_price: 0 + Addon.create category: Addon::CATEGORY_PASS, name: 'Late Departure', default_price: 30 + Addon.create category: Addon::CATEGORY_CAMP, name: 'Car Camping', default_price: 50 + Addon.create category: Addon::CATEGORY_CAMP, name: 'RV under 20ft', default_price: 100 + Addon.create category: Addon::CATEGORY_CAMP, name: 'RV under 25ft', default_price: 125 + Addon.create category: Addon::CATEGORY_CAMP, name: 'RV over 25ft', default_price: 150 + puts "Created #{Addons.count} Addons" + end + def print_event(event) puts puts " Name: #{event.name.to_s.colorize(color: :magenta, mode: :bold)}" diff --git a/db/structure.sql b/db/structure.sql index d7ab5709..b7bf23fa 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -13,6 +13,39 @@ SET default_tablespace = ''; SET default_table_access_method = heap; +-- +-- Name: addons; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.addons ( + id bigint NOT NULL, + category character varying NOT NULL, + name character varying NOT NULL, + default_price integer NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: addons_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.addons_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: addons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.addons_id_seq OWNED BY public.addons.id; + + -- -- Name: ar_internal_metadata; Type: TABLE; Schema: public; Owner: - -- @@ -26,28 +59,33 @@ CREATE TABLE public.ar_internal_metadata ( -- --- Name: eald_payments; Type: TABLE; Schema: public; Owner: - +-- Name: data_migrations; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.data_migrations ( + version character varying NOT NULL +); + + +-- +-- Name: event_addons; Type: TABLE; Schema: public; Owner: - -- -CREATE TABLE public.eald_payments ( - id integer NOT NULL, - event_id integer, - stripe_charge_id character varying NOT NULL, - amount_charged_cents integer NOT NULL, - name character varying(255) NOT NULL, - email character varying(255) NOT NULL, - early_arrival_passes integer DEFAULT 0 NOT NULL, - late_departure_passes integer DEFAULT 0 NOT NULL, - created_at timestamp without time zone, - updated_at timestamp without time zone +CREATE TABLE public.event_addons ( + id bigint NOT NULL, + event_id bigint NOT NULL, + addon_id bigint NOT NULL, + price integer NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL ); -- --- Name: eald_payments_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- Name: event_addons_id_seq; Type: SEQUENCE; Schema: public; Owner: - -- -CREATE SEQUENCE public.eald_payments_id_seq +CREATE SEQUENCE public.event_addons_id_seq START WITH 1 INCREMENT BY 1 NO MINVALUE @@ -56,10 +94,10 @@ CREATE SEQUENCE public.eald_payments_id_seq -- --- Name: eald_payments_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- Name: event_addons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - -- -ALTER SEQUENCE public.eald_payments_id_seq OWNED BY public.eald_payments.id; +ALTER SEQUENCE public.event_addons_id_seq OWNED BY public.event_addons.id; -- @@ -67,11 +105,11 @@ ALTER SEQUENCE public.eald_payments_id_seq OWNED BY public.eald_payments.id; -- CREATE TABLE public.event_admins ( - id integer NOT NULL, - event_id integer, - user_id integer, - created_at timestamp without time zone, - updated_at timestamp without time zone + id bigint NOT NULL, + event_id bigint, + user_id bigint, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL ); @@ -99,20 +137,17 @@ ALTER SEQUENCE public.event_admins_id_seq OWNED BY public.event_admins.id; -- CREATE TABLE public.events ( - id integer NOT NULL, - name character varying(255), + id bigint NOT NULL, + name character varying, start_time timestamp without time zone, end_time timestamp without time zone, - created_at timestamp without time zone, - updated_at timestamp without time zone, - adult_ticket_price numeric(8,2), - kid_ticket_price numeric(8,2), - cabin_price numeric(8,2), + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + adult_ticket_price integer, + kid_ticket_price integer, max_adult_tickets_per_request integer, max_kid_tickets_per_request integer, - max_cabins_per_request integer, - max_cabin_requests integer, - photo character varying(255), + photo character varying, tickets_require_approval boolean DEFAULT true NOT NULL, require_mailing_address boolean DEFAULT false NOT NULL, allow_financial_assistance boolean DEFAULT false NOT NULL, @@ -120,8 +155,6 @@ CREATE TABLE public.events ( ticket_sales_start_time timestamp without time zone, ticket_sales_end_time timestamp without time zone, ticket_requests_end_time timestamp without time zone, - early_arrival_price numeric(8,2) DEFAULT 0, - late_departure_price numeric(8,2) DEFAULT 0, slug text, require_role boolean DEFAULT true NOT NULL ); @@ -151,12 +184,12 @@ ALTER SEQUENCE public.events_id_seq OWNED BY public.events.id; -- CREATE TABLE public.jobs ( - id integer NOT NULL, - event_id integer NOT NULL, + id bigint NOT NULL, + event_id bigint NOT NULL, name character varying(100) NOT NULL, description character varying(512) NOT NULL, - created_at timestamp without time zone, - updated_at timestamp without time zone + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL ); @@ -184,13 +217,13 @@ ALTER SEQUENCE public.jobs_id_seq OWNED BY public.jobs.id; -- CREATE TABLE public.payments ( - id integer NOT NULL, + id bigint NOT NULL, ticket_request_id integer NOT NULL, stripe_charge_id character varying(255), status character varying(1) DEFAULT 'N'::character varying NOT NULL, - created_at timestamp without time zone, - updated_at timestamp without time zone, - explanation character varying(255), + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, + explanation character varying, stripe_payment_id character varying, stripe_refund_id character varying ); @@ -220,13 +253,13 @@ ALTER SEQUENCE public.payments_id_seq OWNED BY public.payments.id; -- CREATE TABLE public.price_rules ( - id integer NOT NULL, - type character varying(255), - event_id integer, + id bigint NOT NULL, + type character varying, + event_id bigint, price numeric(8,2), trigger_value integer, - created_at timestamp without time zone, - updated_at timestamp without time zone + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL ); @@ -254,7 +287,7 @@ ALTER SEQUENCE public.price_rules_id_seq OWNED BY public.price_rules.id; -- CREATE TABLE public.schema_migrations ( - version character varying(255) NOT NULL + version character varying NOT NULL ); @@ -263,12 +296,12 @@ CREATE TABLE public.schema_migrations ( -- CREATE TABLE public.shifts ( - id integer NOT NULL, - time_slot_id integer NOT NULL, - user_id integer NOT NULL, + id bigint NOT NULL, + time_slot_id bigint NOT NULL, + user_id bigint NOT NULL, name character varying(70), - created_at timestamp without time zone, - updated_at timestamp without time zone + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL ); @@ -296,10 +329,10 @@ ALTER SEQUENCE public.shifts_id_seq OWNED BY public.shifts.id; -- CREATE TABLE public.site_admins ( - id integer NOT NULL, + id bigint NOT NULL, user_id integer NOT NULL, - created_at timestamp without time zone, - updated_at timestamp without time zone + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL ); @@ -322,25 +355,57 @@ CREATE SEQUENCE public.site_admins_id_seq ALTER SEQUENCE public.site_admins_id_seq OWNED BY public.site_admins.id; +-- +-- Name: ticket_request_event_addons; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public.ticket_request_event_addons ( + id bigint NOT NULL, + ticket_request_id bigint NOT NULL, + event_addon_id bigint NOT NULL, + quantity integer NOT NULL, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL +); + + +-- +-- Name: ticket_request_event_addons_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE public.ticket_request_event_addons_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: ticket_request_event_addons_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE public.ticket_request_event_addons_id_seq OWNED BY public.ticket_request_event_addons.id; + + -- -- Name: ticket_requests; Type: TABLE; Schema: public; Owner: - -- CREATE TABLE public.ticket_requests ( - id integer NOT NULL, + id bigint NOT NULL, adults integer DEFAULT 1 NOT NULL, kids integer DEFAULT 0 NOT NULL, - cabins integer DEFAULT 0 NOT NULL, needs_assistance boolean DEFAULT false NOT NULL, notes character varying(500), status character varying(1) NOT NULL, - created_at timestamp without time zone, - updated_at timestamp without time zone, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, user_id integer NOT NULL, special_price numeric(8,2), event_id integer NOT NULL, - donation numeric(8,2) DEFAULT 0, - role character varying(255) DEFAULT 'volunteer'::character varying NOT NULL, + donation numeric(8,2) DEFAULT 0.0, + role character varying DEFAULT 'volunteer'::character varying NOT NULL, role_explanation character varying(200), previous_contribution character varying(250), address_line1 character varying(200), @@ -350,11 +415,7 @@ CREATE TABLE public.ticket_requests ( zip_code character varying(32), country_code character varying(4), admin_notes character varying(512), - car_camping boolean, - car_camping_explanation character varying(200), agrees_to_terms boolean, - early_arrival_passes integer DEFAULT 0 NOT NULL, - late_departure_passes integer DEFAULT 0 NOT NULL, guests text, deleted_at timestamp(6) without time zone ); @@ -384,13 +445,13 @@ ALTER SEQUENCE public.ticket_requests_id_seq OWNED BY public.ticket_requests.id; -- CREATE TABLE public.time_slots ( - id integer NOT NULL, - job_id integer NOT NULL, + id bigint NOT NULL, + job_id bigint NOT NULL, start_time timestamp without time zone NOT NULL, end_time timestamp without time zone NOT NULL, slots integer NOT NULL, - created_at timestamp without time zone, - updated_at timestamp without time zone + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL ); @@ -418,26 +479,26 @@ ALTER SEQUENCE public.time_slots_id_seq OWNED BY public.time_slots.id; -- CREATE TABLE public.users ( - id integer NOT NULL, - email character varying(255) NOT NULL, - encrypted_password character varying(255) NOT NULL, - reset_password_token character varying(255), + id bigint NOT NULL, + email character varying NOT NULL, + encrypted_password character varying NOT NULL, + reset_password_token character varying, reset_password_sent_at timestamp without time zone, remember_created_at timestamp without time zone, sign_in_count integer DEFAULT 0, current_sign_in_at timestamp without time zone, last_sign_in_at timestamp without time zone, - current_sign_in_ip character varying(255), - last_sign_in_ip character varying(255), - confirmation_token character varying(255), + current_sign_in_ip character varying, + last_sign_in_ip character varying, + confirmation_token character varying, confirmed_at timestamp without time zone, confirmation_sent_at timestamp without time zone, - unconfirmed_email character varying(255), + unconfirmed_email character varying, failed_attempts integer DEFAULT 0, - unlock_token character varying(255), + unlock_token character varying, locked_at timestamp without time zone, - created_at timestamp without time zone, - updated_at timestamp without time zone, + created_at timestamp(6) without time zone NOT NULL, + updated_at timestamp(6) without time zone NOT NULL, name character varying(70) NOT NULL, authentication_token character varying(64), first text, @@ -465,10 +526,17 @@ ALTER SEQUENCE public.users_id_seq OWNED BY public.users.id; -- --- Name: eald_payments id; Type: DEFAULT; Schema: public; Owner: - +-- Name: addons id; Type: DEFAULT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.eald_payments ALTER COLUMN id SET DEFAULT nextval('public.eald_payments_id_seq'::regclass); +ALTER TABLE ONLY public.addons ALTER COLUMN id SET DEFAULT nextval('public.addons_id_seq'::regclass); + + +-- +-- Name: event_addons id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_addons ALTER COLUMN id SET DEFAULT nextval('public.event_addons_id_seq'::regclass); -- @@ -520,6 +588,13 @@ ALTER TABLE ONLY public.shifts ALTER COLUMN id SET DEFAULT nextval('public.shift ALTER TABLE ONLY public.site_admins ALTER COLUMN id SET DEFAULT nextval('public.site_admins_id_seq'::regclass); +-- +-- Name: ticket_request_event_addons id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.ticket_request_event_addons ALTER COLUMN id SET DEFAULT nextval('public.ticket_request_event_addons_id_seq'::regclass); + + -- -- Name: ticket_requests id; Type: DEFAULT; Schema: public; Owner: - -- @@ -541,6 +616,14 @@ ALTER TABLE ONLY public.time_slots ALTER COLUMN id SET DEFAULT nextval('public.t ALTER TABLE ONLY public.users ALTER COLUMN id SET DEFAULT nextval('public.users_id_seq'::regclass); +-- +-- Name: addons addons_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.addons + ADD CONSTRAINT addons_pkey PRIMARY KEY (id); + + -- -- Name: ar_internal_metadata ar_internal_metadata_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -550,11 +633,19 @@ ALTER TABLE ONLY public.ar_internal_metadata -- --- Name: eald_payments eald_payments_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- Name: data_migrations data_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.data_migrations + ADD CONSTRAINT data_migrations_pkey PRIMARY KEY (version); + + +-- +-- Name: event_addons event_addons_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- -ALTER TABLE ONLY public.eald_payments - ADD CONSTRAINT eald_payments_pkey PRIMARY KEY (id); +ALTER TABLE ONLY public.event_addons + ADD CONSTRAINT event_addons_pkey PRIMARY KEY (id); -- @@ -597,6 +688,14 @@ ALTER TABLE ONLY public.price_rules ADD CONSTRAINT price_rules_pkey PRIMARY KEY (id); +-- +-- Name: schema_migrations schema_migrations_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.schema_migrations + ADD CONSTRAINT schema_migrations_pkey PRIMARY KEY (version); + + -- -- Name: shifts shifts_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -613,6 +712,14 @@ ALTER TABLE ONLY public.site_admins ADD CONSTRAINT site_admins_pkey PRIMARY KEY (id); +-- +-- Name: ticket_request_event_addons ticket_request_event_addons_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.ticket_request_event_addons + ADD CONSTRAINT ticket_request_event_addons_pkey PRIMARY KEY (id); + + -- -- Name: ticket_requests ticket_requests_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -637,6 +744,20 @@ ALTER TABLE ONLY public.users ADD CONSTRAINT users_pkey PRIMARY KEY (id); +-- +-- Name: index_event_addons_on_addon_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_addons_on_addon_id ON public.event_addons USING btree (addon_id); + + +-- +-- Name: index_event_addons_on_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_event_addons_on_event_id ON public.event_addons USING btree (event_id); + + -- -- Name: index_event_admins_on_event_id_and_user_id; Type: INDEX; Schema: public; Owner: - -- @@ -651,6 +772,13 @@ CREATE UNIQUE INDEX index_event_admins_on_event_id_and_user_id ON public.event_a CREATE INDEX index_event_admins_on_user_id ON public.event_admins USING btree (user_id); +-- +-- Name: index_jobs_on_event_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_jobs_on_event_id ON public.jobs USING btree (event_id); + + -- -- Name: index_payments_on_stripe_payment_id; Type: INDEX; Schema: public; Owner: - -- @@ -665,6 +793,34 @@ CREATE INDEX index_payments_on_stripe_payment_id ON public.payments USING btree CREATE INDEX index_price_rules_on_event_id ON public.price_rules USING btree (event_id); +-- +-- Name: index_shifts_on_time_slot_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_shifts_on_time_slot_id ON public.shifts USING btree (time_slot_id); + + +-- +-- Name: index_shifts_on_user_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_shifts_on_user_id ON public.shifts USING btree (user_id); + + +-- +-- Name: index_ticket_request_event_addons_on_event_addon_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_ticket_request_event_addons_on_event_addon_id ON public.ticket_request_event_addons USING btree (event_addon_id); + + +-- +-- Name: index_ticket_request_event_addons_on_ticket_request_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_ticket_request_event_addons_on_ticket_request_id ON public.ticket_request_event_addons USING btree (ticket_request_id); + + -- -- Name: index_ticket_requests_on_deleted_at; Type: INDEX; Schema: public; Owner: - -- @@ -672,6 +828,13 @@ CREATE INDEX index_price_rules_on_event_id ON public.price_rules USING btree (ev CREATE INDEX index_ticket_requests_on_deleted_at ON public.ticket_requests USING btree (deleted_at) WHERE (deleted_at IS NULL); +-- +-- Name: index_time_slots_on_job_id; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX index_time_slots_on_job_id ON public.time_slots USING btree (job_id); + + -- -- Name: index_users_on_confirmation_token; Type: INDEX; Schema: public; Owner: - -- @@ -701,10 +864,35 @@ CREATE UNIQUE INDEX index_users_on_unlock_token ON public.users USING btree (unl -- --- Name: unique_schema_migrations; Type: INDEX; Schema: public; Owner: - +-- Name: event_addons fk_rails_06009452ef; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_addons + ADD CONSTRAINT fk_rails_06009452ef FOREIGN KEY (addon_id) REFERENCES public.addons(id); + + +-- +-- Name: event_addons fk_rails_784eec636d; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.event_addons + ADD CONSTRAINT fk_rails_784eec636d FOREIGN KEY (event_id) REFERENCES public.events(id); + + +-- +-- Name: ticket_request_event_addons fk_rails_847e21fcca; Type: FK CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public.ticket_request_event_addons + ADD CONSTRAINT fk_rails_847e21fcca FOREIGN KEY (ticket_request_id) REFERENCES public.ticket_requests(id); + + +-- +-- Name: ticket_request_event_addons fk_rails_b0497bfcb6; Type: FK CONSTRAINT; Schema: public; Owner: - -- -CREATE UNIQUE INDEX unique_schema_migrations ON public.schema_migrations USING btree (version); +ALTER TABLE ONLY public.ticket_request_event_addons + ADD CONSTRAINT fk_rails_b0497bfcb6 FOREIGN KEY (event_addon_id) REFERENCES public.event_addons(id); -- @@ -714,6 +902,10 @@ CREATE UNIQUE INDEX unique_schema_migrations ON public.schema_migrations USING b SET search_path TO "$user", public; INSERT INTO "schema_migrations" (version) VALUES +('20240729210234'), +('20240728223048'), +('20240728211432'), +('20240718224717'), ('20240710231611'), ('20240523173316'), ('20240516225937'), diff --git a/spec/controllers/events_controller_spec.rb b/spec/controllers/events_controller_spec.rb index 20f5c132..5f50d93b 100644 --- a/spec/controllers/events_controller_spec.rb +++ b/spec/controllers/events_controller_spec.rb @@ -71,6 +71,7 @@ before do allow_any_instance_of(described_class).to receive(:params).and_return(ActionController::Parameters.new(event: new_event_params)) end + # rubocop: enable RSpec/AnyInstance it 'does not have a nil start_time' do expect(new_event.start_time).not_to be_nil @@ -84,41 +85,6 @@ expect(new_event.require_role).to be_truthy end - # rubocop: enable RSpec/AnyInstance - - describe '#permitted_params' do - subject(:permitted_keys) { permitted_event_keys } - - let(:permitted_event_params) { described_class.new.send(:permitted_params)[:event].to_h.symbolize_keys } - let(:expected_keys) do - %i[ - adult_ticket_price - allow_donations - allow_financial_assistance - cabin_price - early_arrival_price - end_time - kid_ticket_price - late_departure_price - max_adult_tickets_per_request - max_cabin_requests - max_cabins_per_request - max_kid_tickets_per_request - name - require_mailing_address - require_role - start_time - ticket_requests_end_time - ticket_sales_end_time - ticket_sales_start_time - tickets_require_approval - ] - end - let(:permitted_event_keys) { permitted_event_params.keys.sort } - - it { expect(permitted_keys).to eql(expected_keys) } - end - context 'when the user is not signed in' do before { make_request[] } diff --git a/spec/factories/addon.rb b/spec/factories/addon.rb new file mode 100644 index 00000000..629da101 --- /dev/null +++ b/spec/factories/addon.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :addon do + category { Addon::CATEGORY_PASS } + name { 'Backstage' } + default_price { 20 } + end +end diff --git a/spec/factories/eald_payment.rb b/spec/factories/eald_payment.rb deleted file mode 100644 index 2cedea1a..00000000 --- a/spec/factories/eald_payment.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -FactoryBot.define do - factory :eald_payment do - event - name { Faker::Name.name } - early_arrival_passes { 10 } - amount_charged_cents { 1000 } - late_departure_passes { 5 } - email { Faker::Internet.email } - stripe_charge_id { Faker::Alphanumeric.alphanumeric(number: 10) } - end -end diff --git a/spec/factories/event.rb b/spec/factories/event.rb index cacd1182..0f81ca9f 100644 --- a/spec/factories/event.rb +++ b/spec/factories/event.rb @@ -10,21 +10,14 @@ adult_ticket_price { Random.rand(100..150) } kid_ticket_price { Random.rand(40..50) } - cabin_price { nil } max_adult_tickets_per_request { Random.rand(2..4) } max_kid_tickets_per_request { 2 } - max_cabins_per_request { nil } tickets_require_approval { true } trait :kids_tickets_available do kid_ticket_price { Random.rand(10) } end - trait :cabins_available do - cabin_price { Random.rand(100) } - max_cabins_per_request { Random.rand(1...1) } - end - trait :with_admins do after(:create) do |event| create_list(:event_admin, 2, event:) diff --git a/spec/factories/event_addon.rb b/spec/factories/event_addon.rb new file mode 100644 index 00000000..916888cf --- /dev/null +++ b/spec/factories/event_addon.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :event_addon do + event + addon + price { 10 } + end +end diff --git a/spec/factories/ticket_request.rb b/spec/factories/ticket_request.rb index 2c6b54c9..5c62fb49 100644 --- a/spec/factories/ticket_request.rb +++ b/spec/factories/ticket_request.rb @@ -4,7 +4,6 @@ factory :ticket_request do adults { event&.max_adult_tickets_per_request || 1 } kids { Random.rand(2) } - cabins { Random.rand(2) } needs_assistance { [true, false].sample } notes { Faker::Lorem.paragraph } agrees_to_terms { true } diff --git a/spec/factories/ticket_request_event_addon.rb b/spec/factories/ticket_request_event_addon.rb new file mode 100644 index 00000000..f869126d --- /dev/null +++ b/spec/factories/ticket_request_event_addon.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :ticket_request_event_addon do + event_addon + ticket_request + quantity { 1 } + end +end diff --git a/spec/mailers/eald_payment_mailer_spec.rb b/spec/mailers/eald_payment_mailer_spec.rb deleted file mode 100644 index cd890d80..00000000 --- a/spec/mailers/eald_payment_mailer_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe EaldPaymentMailer do - let(:payment) { create(:eald_payment) } - let(:event) { payment.event } - - describe '#eald_payment_received' do - subject(:mail) { described_class.eald_payment_received(payment) } - - let(:expected_subject) { "Your payment for #{event.name} Early Arrival/Late Departure passes has been received" } - - its(:subject) { is_expected.to eql(expected_subject) } - - its(:to) { is_expected.to eql([payment.email]) } - - its('body.encoded') { is_expected.to match(event.name) } - end -end diff --git a/spec/models/addon_spec.rb b/spec/models/addon_spec.rb new file mode 100644 index 00000000..d00b5f95 --- /dev/null +++ b/spec/models/addon_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: addons +# +# id :bigint not null, primary key +# category :string not null +# default_price :integer not null +# name :string not null +# created_at :datetime not null +# updated_at :datetime not null +# +require 'rails_helper' + +RSpec.describe Addon do + describe 'validations' do + subject { addon } + + describe '#category' do + context 'when category is known' do + let(:addon) { build(:addon, category: Addon::CATEGORY_PASS) } + + it { is_expected.to be_valid } + end + + context 'when category unknown' do + let(:addon) { build(:addon, category: 'foo') } + + it { is_expected.not_to be_valid } + end + end + + describe '#name' do + context 'when name not present' do + let(:addon) { build(:addon, name: nil) } + + it { is_expected.not_to be_valid } + end + end + + describe '#default_price' do + context 'when default price not present' do + let(:addon) { build(:addon, default_price: nil) } + + it { is_expected.not_to be_valid } + end + + context 'when default price negative' do + let(:addon) { build(:addon, default_price: -1) } + + it { is_expected.not_to be_valid } + end + end + end +end diff --git a/spec/models/event_addon_spec.rb b/spec/models/event_addon_spec.rb new file mode 100644 index 00000000..3b0525bf --- /dev/null +++ b/spec/models/event_addon_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: event_addons +# +# id :bigint not null, primary key +# price :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# addon_id :bigint not null +# event_id :bigint not null +# +# Indexes +# +# index_event_addons_on_addon_id (addon_id) +# index_event_addons_on_event_id (event_id) +# +# Foreign Keys +# +# fk_rails_... (addon_id => addons.id) +# fk_rails_... (event_id => events.id) +# + +require 'rails_helper' + +RSpec.describe EventAddon do + describe 'validations' do + subject { event_addon } + + let(:event_addon) { build(:event_addon) } + + describe '#price' do + it { is_expected.to be_valid } + + describe '#set_default_values' do + let(:event_addon) { build(:event_addon, price: nil) } + + it 'has price set to default price' do + expect(event_addon.set_default_values).to eq(event_addon.addon.default_price) + end + end + + context 'when price is set' do + let(:price) { 314 } + let(:event_addon) { build(:event_addon, price:) } + + it 'has price set' do + expect(event_addon.price).to eq(price) + end + end + end + end +end diff --git a/spec/models/event_admin_spec.rb b/spec/models/event_admin_spec.rb index bf68cc03..dea28545 100644 --- a/spec/models/event_admin_spec.rb +++ b/spec/models/event_admin_spec.rb @@ -14,6 +14,7 @@ # # index_event_admins_on_event_id_and_user_id (event_id,user_id) UNIQUE # index_event_admins_on_user_id (user_id) +# require 'rails_helper' describe EventAdmin do diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 2b5d2594..80550238 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -5,21 +5,18 @@ # Table name: events # # id :bigint not null, primary key -# adult_ticket_price :decimal(8, 2) +# adult_ticket_price :integer # allow_donations :boolean default(FALSE), not null # allow_financial_assistance :boolean default(FALSE), not null -# cabin_price :decimal(8, 2) -# early_arrival_price :decimal(8, 2) default(0.0) # end_time :datetime -# kid_ticket_price :decimal(8, 2) -# late_departure_price :decimal(8, 2) default(0.0) +# kid_ticket_price :integer # max_adult_tickets_per_request :integer -# max_cabin_requests :integer -# max_cabins_per_request :integer # max_kid_tickets_per_request :integer # name :string # photo :string # require_mailing_address :boolean default(FALSE), not null +# require_role :boolean default(TRUE), not null +# slug :text # start_time :datetime # ticket_requests_end_time :datetime # ticket_sales_end_time :datetime @@ -27,6 +24,7 @@ # tickets_require_approval :boolean default(TRUE), not null # created_at :datetime not null # updated_at :datetime not null +# require 'rails_helper' @@ -137,11 +135,6 @@ it { is_expected.not_to accept_values_for(:kid_ticket_price, -1) } end - describe '#cabin_price' do - it { is_expected.to accept_values_for(:cabin_price, nil, '', 0, 50) } - it { is_expected.not_to accept_values_for(:cabin_price, -1) } - end - describe '#max_adult_tickets_per_request' do it { is_expected.to accept_values_for(:max_adult_tickets_per_request, nil, '', 50) } it { is_expected.not_to accept_values_for(:max_adult_tickets_per_request, 0, -1) } @@ -154,43 +147,6 @@ it { is_expected.to accept_values_for(:max_kid_tickets_per_request, nil, '', 10) } it { is_expected.not_to accept_values_for(:max_kid_tickets_per_request, 0, -1) } end - - context 'when kid_ticket_price is not set' do - subject { build(:event, kid_ticket_price: nil) } - - it { is_expected.not_to accept_values_for(:max_kid_tickets_per_request, 10) } - end - end - - describe '#max_cabins_per_request' do - context 'when cabin_price is set' do - subject { build(:event, cabin_price: 10) } - - it { is_expected.to accept_values_for(:max_cabins_per_request, nil, '', 10) } - it { is_expected.not_to accept_values_for(:max_cabins_per_request, 0, -1) } - end - - context 'when cabin_price is not set' do - subject { build(:event, cabin_price: nil) } - - it { is_expected.not_to accept_values_for(:max_cabins_per_request, 10) } - end - end - - describe '#max_cabin_requests' do - context 'when cabin_price is set' do - subject { build(:event, cabin_price: 10) } - - it { is_expected.to accept_values_for(:max_cabin_requests, nil, '', 10) } - it { is_expected.not_to accept_values_for(:max_cabin_requests, 0, -1) } - end - - context 'when cabin_price is not set' do - subject { build(:event, cabin_price: nil) } - - it { is_expected.to accept_values_for(:max_cabin_requests, nil, '') } - it { is_expected.not_to accept_values_for(:max_cabin_requests, 10) } - end end end @@ -227,47 +183,6 @@ end end - describe '#cabins_available?' do - subject { event.cabins_available? } - - let(:event) { create(:event, cabin_price:, max_cabin_requests:) } - - let(:cabin_price) { nil } - let(:max_cabin_requests) { nil } - - context 'when no cabin price is set' do - let(:cabin_price) { nil } - - it { is_expected.to be false } - end - - context 'when cabin price is set' do - let(:cabin_price) { 100 } - - context 'when no maximum specified for the number of cabin requests' do - let(:max_cabin_requests) { nil } - - it { is_expected.to be true } - end - - context 'when a maximum is specified for the number of cabin requests' do - let(:max_cabin_requests) { 10 } - - context 'when there are fewer cabins requested than the maximum' do - it { is_expected.to be true } - end - - context 'when the number of cabins requested has met or exceeded the maximum' do - before do - create(:ticket_request, event:, cabins: max_cabin_requests) - end - - it { is_expected.to be false } - end - end - end - end - describe '#ticket_sales_open?' do subject { event.ticket_sales_open? } @@ -368,4 +283,108 @@ end end end + + describe '#build_event_addons_from_params' do + let(:price) { 314 } + + context 'event addon is built for event' do + let!(:addon) { create(:addon) } + + before do + event_addons_attributes = { '0'=>{ 'addon_id' => addon.id.to_s, 'price' => price.to_s } } + event.build_event_addons_from_params(event_addons_attributes) + end + + it 'has 1 event addon' do + expect(event.event_addons.size).to eq(1) + end + + it 'has price set from params' do + expect(event.event_addons.first&.price).to eq(price) + end + + it 'has addon id set from params' do + expect(event.event_addons.first&.addon_id).to eq(addon.id) + end + end + + context 'event addon is not built for event' do + before do + event_addons_attributes = { '0'=>{ 'addon_id' => 999, 'price' => price.to_s } } + event.build_event_addons_from_params(event_addons_attributes) + end + + it 'has an unknown addon id' do + expect(event.event_addons.size).to eq(0) + end + end + end + + describe '#create_default_event_addons' do + context 'event has no addons' do + it 'event has no addons' do + expect(event.event_addons.count).to eq(0) + end + end + + context 'event has event addons' do + before do + create(:addon) + event.create_default_event_addons + end + + it 'creates and persists an EventAddon' do + expect(EventAddon.count).to eq(1) + end + + it 'creates EventAddon with name' do + expect(EventAddon.first&.name).to eq(Addon.first.name) + end + + it 'event has event addons for each Addon' do + expect(event.event_addons.size).to eq(Addon.count) + end + + it 'event has default prices for addons' do + event_addon = event.event_addons.first + expect(event_addon&.price).to eq(event_addon&.addon&.default_price) + end + end + end + + describe '#load_default_event_addons' do + context 'event has no addons' do + it 'event has no addons' do + expect(event.event_addons.count).to eq(0) + end + end + + context 'event has event addons' do + before do + create(:addon) + event.build_default_event_addons + end + + it 'event has event addons for each Addon' do + expect(event.event_addons.size).to eq(Addon.count) + end + + it 'event addons are not saved' do + expect(event.event_addons.first&.persisted?).to be_falsey + end + end + end + + describe '#active_event_addons' do + let!(:event) { create(:event) } + let!(:event_addon) { create(:event_addon, event_id: event.id) } + + it 'has a price not 0' do + expect(event_addon.price).not_to eq(0) + end + + it 'finds one active event' do + expect(event.active_event_addons.count).to eq(1) + end + end end diff --git a/spec/models/payment_spec.rb b/spec/models/payment_spec.rb index 64fc080b..d6d4be43 100644 --- a/spec/models/payment_spec.rb +++ b/spec/models/payment_spec.rb @@ -4,13 +4,20 @@ # # Table name: payments # -# id :integer not null, primary key -# explanation :string(255) -# status :string(1) default("P"), not null -# created_at :datetime -# updated_at :datetime +# id :bigint not null, primary key +# explanation :string +# status :string(1) default("N"), not null +# created_at :datetime not null +# updated_at :datetime not null # stripe_charge_id :string(255) +# stripe_payment_id :string +# stripe_refund_id :string # ticket_request_id :integer not null +# +# Indexes +# +# index_payments_on_stripe_payment_id (stripe_payment_id) +# require 'rails_helper' diff --git a/spec/models/site_admin_spec.rb b/spec/models/site_admin_spec.rb index d9158674..11682d85 100644 --- a/spec/models/site_admin_spec.rb +++ b/spec/models/site_admin_spec.rb @@ -8,6 +8,7 @@ # created_at :datetime not null # updated_at :datetime not null # user_id :integer not null +# require 'rails_helper' diff --git a/spec/models/ticket_request_event_addon_spec.rb b/spec/models/ticket_request_event_addon_spec.rb new file mode 100644 index 00000000..e2837ef2 --- /dev/null +++ b/spec/models/ticket_request_event_addon_spec.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +# == Schema Information +# +# Table name: ticket_request_event_addons +# +# id :bigint not null, primary key +# quantity :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# event_addon_id :bigint not null +# ticket_request_id :bigint not null +# +# Indexes +# +# index_ticket_request_event_addons_on_event_addon_id (event_addon_id) +# index_ticket_request_event_addons_on_ticket_request_id (ticket_request_id) +# +# Foreign Keys +# +# fk_rails_... (event_addon_id => event_addons.id) +# fk_rails_... (ticket_request_id => ticket_requests.id) +# +require 'rails_helper' + +RSpec.describe TicketRequestEventAddon, type: :model do + describe 'validations' do + subject { ticket_request_event_addon } + + let(:ticket_request_event_addon) { build(:ticket_request_event_addon) } + + describe '#quantity' do + context 'when valid quantity' do + let(:ticket_request_event_addon) { build(:ticket_request_event_addon, quantity: 2) } + + it { is_expected.to be_valid } + end + + context 'when invalid quantity' do + let(:ticket_request_event_addon) { build(:ticket_request_event_addon, quantity: -1) } + + it { is_expected.not_to be_valid } + end + end + end +end diff --git a/spec/models/ticket_request_spec.rb b/spec/models/ticket_request_spec.rb index be9aed10..7119d95e 100644 --- a/spec/models/ticket_request_spec.rb +++ b/spec/models/ticket_request_spec.rb @@ -10,16 +10,12 @@ # admin_notes :string(512) # adults :integer default(1), not null # agrees_to_terms :boolean -# cabins :integer default(0), not null -# car_camping :boolean -# car_camping_explanation :string(200) # city :string(50) # country_code :string(4) +# deleted_at :datetime # donation :decimal(8, 2) default(0.0) -# early_arrival_passes :integer default(0), not null # guests :text # kids :integer default(0), not null -# late_departure_passes :integer default(0), not null # needs_assistance :boolean default(FALSE), not null # notes :string(500) # previous_contribution :string(250) @@ -33,6 +29,11 @@ # updated_at :datetime not null # event_id :integer not null # user_id :integer not null +# +# Indexes +# +# index_ticket_requests_on_deleted_at (deleted_at) WHERE (deleted_at IS NULL) +# require 'rails_helper' @@ -135,28 +136,6 @@ end end - describe '#cabins' do - let(:ticket_request) { build(:ticket_request, cabins:) } - - context 'when not present' do - let(:cabins) { nil } - - it { is_expected.to be_valid } - end - - context 'when not a number' do - let(:cabins) { 'not a number' } - - it { is_expected.not_to be_valid } - end - - context 'when a number' do - let(:cabins) { 2 } - - it { is_expected.to be_valid } - end - end - describe '#notes' do let(:ticket_request) { build(:ticket_request, notes:) } @@ -287,21 +266,17 @@ let(:adults) { 2 } let(:kid_price) { nil } let(:kids) { nil } - let(:cabin_price) { nil } - let(:cabins) { nil } let(:special_price) { nil } let(:event) do build(:event, adult_ticket_price: adult_price, - kid_ticket_price: kid_price, - cabin_price:) + kid_ticket_price: kid_price) end let(:ticket_request) do build(:ticket_request, event:, adults:, kids:, - cabins:, special_price:) end @@ -322,47 +297,21 @@ it { is_expected.to eql(adult_price * adults) } end - context 'when the ticket request includes cabins' do - let(:cabins) { 2 } - let(:cabin_price) { 100 } - - it { is_expected.to eql((adult_price * adults) + (cabin_price * cabins)) } - end - - context 'when the ticket request does not include cabins' do - let(:cabins) { nil } - - it { is_expected.to eql(adult_price * adults) } - end - context 'when a special price is set' do let(:special_price) { BigDecimal(99.99, 10) } it { is_expected.to eql(special_price) } end + end - context 'when custom price rules are defined' do - let(:kid_price) { 10 } - let(:trigger_value) { 3 } - let(:custom_price) { 5 } - - before do - PriceRule::KidsEqualTo.create! event:, - trigger_value:, - price: custom_price - end - - context 'and the rule does not apply' do - let(:kids) { trigger_value - 1 } - - it { is_expected.to eql((adult_price * adults) + (kid_price * kids)) } - end - - context 'and the rule applies' do - let(:kids) { trigger_value } + describe '#calculate_addons_price' do + let!(:event) { create(:event) } + let!(:event_addon) { create(:event_addon, price: 10) } + let!(:ticket_request) { create(:ticket_request, event_id: event.id) } + let!(:ticket_request_event_addon) { create(:ticket_request_event_addon, ticket_request_id: ticket_request.id, quantity: 1) } - it { is_expected.to eql((adult_price * adults) + 5) } - end + it 'calculates event addons price for ticket request' do + expect(ticket_request.calculate_addons_price).to eq(event_addon.price * ticket_request_event_addon.quantity) end end