diff --git a/.version b/.version index e05cb332..d4c4950a 100644 --- a/.version +++ b/.version @@ -1 +1 @@ -1.3.8 +1.3.9 diff --git a/app/classes/fnf/events/ticket_request_event.rb b/app/classes/fnf/events/ticket_request_event.rb index 108950e5..d39fe1db 100644 --- a/app/classes/fnf/events/ticket_request_event.rb +++ b/app/classes/fnf/events/ticket_request_event.rb @@ -10,6 +10,7 @@ class TicketRequestEvent < AbstractEvent def initialize(user: nil, target: nil) super + Rails.logger.info("TicketRequestEvent: target: #{target}") self.ticket_request = target end end diff --git a/app/controllers/ticket_requests_controller.rb b/app/controllers/ticket_requests_controller.rb index ca67330d..f337532e 100644 --- a/app/controllers/ticket_requests_controller.rb +++ b/app/controllers/ticket_requests_controller.rb @@ -134,24 +134,25 @@ def create @ticket_request.save! Rails.logger.info("Saved Ticket Request, ID = #{@ticket_request.id}") - FnF::Events::TicketRequestEvent.new( - user: ticket_request_user, - target: @ticket_request - ).fire! + if @event.tickets_require_approval + TicketRequestMailer.request_received(@ticket_request).deliver_later - 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 !@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).' + else + TicketRequestMailer.request_confirmed(@ticket_request).deliver_later + + if !@ticket_request.all_guests_specified? + Rails.logger.debug { "tr NOT all guests specified: #{@ticket_request.inspect}" } + 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? + 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 end rescue StandardError => e Rails.logger.error("Error Processing Ticket Send Request: #{e.message}\n\n#{@ticket_request.errors.full_messages.join(', ')}") @@ -194,11 +195,10 @@ def destroy end def approve + # update approved if @ticket_request.approve - ::FnF::Events::TicketRequestApprovedEvent.new( - user: current_user, - target: @ticket_request - ).fire! + TicketRequestMailer.request_approved(@ticket_request).deliver_later + redirect_to event_ticket_requests_path(@event), notice: "#{@ticket_request.user.name}'s request was approved" else @@ -208,11 +208,9 @@ def approve end def decline - if @ticket_request.update(status: TicketRequest::STATUS_DECLINED) - ::FnF::Events::TicketRequestDeclinedEvent.new( - user: current_user, - target: @ticket_request - ).fire! + if @ticket_request.mark_declined + TicketRequestMailer.request_denied(@ticket_request).deliver_later + redirect_to event_ticket_requests_path(@event), error: "#{@ticket_request.user.name}'s request was declined" else diff --git a/app/mailers/ticket_request_mailer.rb b/app/mailers/ticket_request_mailer.rb index 2bde4292..7676a192 100644 --- a/app/mailers/ticket_request_mailer.rb +++ b/app/mailers/ticket_request_mailer.rb @@ -23,7 +23,36 @@ def request_received(ticket_request) mail to: to_email, # The recipient of the email from: from_email, # The sender of the email reply_to: reply_to_email, # The email address that will receive replies - subject: "#{@event.name} ticket request confirmation" # The subject of the email + subject: "#{@event.name} ticket request received!" # The subject of the email + end + + # The `request_confirmed` method is used to send an email when a ticket request is confirmed without approval. + # It sets the ticket request and then sends an email to the user who made the request. + # + # @param ticket_request [TicketRequest] The ticket request that has been confirmed + # @return [Mail::Message] The email that has been prepared to be sent. + def request_confirmed(ticket_request) + # Set the ticket request + self.ticket_request = ticket_request + + # Generate an authentication token for the user + @auth_token = ticket_request&.user&.generate_auth_token! + + # Return if the authentication token is blank + if @auth_token.blank? + Rails.logger.warn { "request_confirmed: no auth token for user: #{@ticket_request.inspect}" } + return + end + + @payment_url = new_event_ticket_request_payment_url(@event, @ticket_request, @auth_token) + @ticket_request_url = event_ticket_request_url(event_id: @event.id, id: @ticket_request.id) + Rails.logger.debug { "request_confirmed: payment_url: #{@payment_url} ticket_request_url: #{@ticket_request_url}" } + + # Prepare the email to be sent + mail to: to_email, # The recipient of the email + from: from_email, # The sender of the email + reply_to: reply_to_email, # The email address that will receive replies + subject: "#{@event.name} ticket confirmation!" # The subject of the email end # The `request_approved` method is used to send an email when a ticket request is approved. @@ -39,11 +68,12 @@ def request_approved(ticket_request) # Generate an authentication token for the user @auth_token = ticket_request&.user&.generate_auth_token! - @payment_url = new_event_ticket_request_payment_url(@event, @ticket_request, @auth_token) - # Return if the authentication token is blank return if @auth_token.blank? + @payment_url = new_event_ticket_request_payment_url(@event, @ticket_request, @auth_token) + @ticket_request_url = event_ticket_request_url(event_id: @event.id, id: @ticket_request.id) + # Prepare the email to be sent mail to: to_email, # The recipient of the email from: from_email, # The sender of the email @@ -51,6 +81,21 @@ def request_approved(ticket_request) subject: "Your #{@event.name} ticket request has been approved!" # The subject of the email end + # The `request_denied` method is used to send an email when a ticket request is denied for reasons. + # @param ticket_request [TicketRequest] The ticket request that has been denied. + # + # @return [Mail::Message, nil] The email that has been prepared to be sent, or nil if the authentication token is blank. + def request_denied(ticket_request) + # Set the ticket request + self.ticket_request = ticket_request + + # Prepare the email to be sent + mail to: to_email, # The recipient of the email + from: from_email, # The sender of the email + reply_to: reply_to_email, # The email address that will ¬receive replies + subject: "Your #{@event.name} ticket request" # The subject of the email + end + private def ticket_request=(ticket_request) @@ -68,15 +113,19 @@ def mail_config end def ticket_request(event) - request_received(event.ticket_request).deliver_now + request_received(event.ticket_request).deliver_later + end + + def ticket_request_confirmed(event) + request_confirmed(event.ticket_request).deliver_later end def ticket_request_approved(event) - request_approved(event.ticket_request).deliver_now + request_approved(event.ticket_request).deliver_later end - def ticket_request_declined(_) - # Not yet implemented + def ticket_request_declined(event) + request_denied(event.ticket_request).deliver_later end end end diff --git a/app/models/ticket_request.rb b/app/models/ticket_request.rb index db08479e..db99df29 100644 --- a/app/models/ticket_request.rb +++ b/app/models/ticket_request.rb @@ -239,6 +239,10 @@ def mark_refunded update status: STATUS_REFUNDED end + def mark_declined + update status: STATUS_DECLINED + end + def payment_received? payment&.status_received? end diff --git a/app/views/ticket_request_mailer/request_approved.html.haml b/app/views/ticket_request_mailer/request_approved.html.haml index 3f8c64bc..277ac46a 100644 --- a/app/views/ticket_request_mailer/request_approved.html.haml +++ b/app/views/ticket_request_mailer/request_approved.html.haml @@ -1,21 +1,26 @@ %p Hi #{@ticket_request.user.first_name}, + %p Your ticket request for %b #{@event.name} has been approved! -%p<> +%p - if @ticket_request.free? You're good to go! - else - You can now - = succeed '.' do - = link_to @payment_url do - purchase your - = 'ticket'.pluralize(@ticket_request.total_tickets) + You can + = link_to @payment_url do + buy your + = 'ticket'.pluralize(@ticket_request.total_tickets) + now! %p - Thanks, + With love ❤️, %br - The FnF Ticket Team + Your FnF Ticket Team + +%p + P.S. You can view the status of your request at any time by visiting + = link_to 'this page', @ticket_request_url diff --git a/app/views/ticket_request_mailer/request_confirmed.html.haml b/app/views/ticket_request_mailer/request_confirmed.html.haml new file mode 100644 index 00000000..8b0aee7f --- /dev/null +++ b/app/views/ticket_request_mailer/request_confirmed.html.haml @@ -0,0 +1,39 @@ +%p + Hi #{@ticket_request.user.first_name}, + +%p + Your + = 'ticket'.pluralize(@ticket_request.total_tickets) + for + %b #{@event.name} + - @ticket_request.total_tickets > 1 ? ' are ' : ' is ' + confirmed! + +%p + Total Tickets: #{@ticket_request.total_tickets} + - if @ticket_request.ticket_request_event_addons? + %br + Event Addons: + - @ticket_request.active_sorted_addons.each do |tr_event_addon| + = "#{tr_event_addon.name}: #{tr_event_addon.quantity}" + %br +%p + - if @ticket_request.free? + You're good to go! + - else + If you have not already paid for your tickets, + = link_to @payment_url do + buy your tickets now! + +%p + With love ❤️, + %br + Your FnF Ticket Team + +%p + P.S. You can view the status of your request at any time by visiting + = link_to 'this page', @ticket_request_url + +%p +%p + %i This email was generated by a very friendly hamster at: #{Time.now} \ No newline at end of file diff --git a/app/views/ticket_request_mailer/request_denied.html.haml b/app/views/ticket_request_mailer/request_denied.html.haml new file mode 100644 index 00000000..398c8af0 --- /dev/null +++ b/app/views/ticket_request_mailer/request_denied.html.haml @@ -0,0 +1,13 @@ +%p + Hi #{@ticket_request.user.first_name}, +%p + Your ticket request for + %b #{@event.name} + has been declined or denied. + +%p + If you feel that this is an error, or would like more information, + please reply directly to this email. + +%p + \- The FnF Ticket Team diff --git a/app/views/ticket_request_mailer/request_received.html.haml b/app/views/ticket_request_mailer/request_received.html.haml index ca053517..71802d56 100644 --- a/app/views/ticket_request_mailer/request_received.html.haml +++ b/app/views/ticket_request_mailer/request_received.html.haml @@ -2,8 +2,14 @@ Hi #{@ticket_request.user.first_name}, %p - We have received your ticket request for #{@event.name} for - #{@ticket_request.total_tickets} total tickets (including kids). + We have received your ticket request for #{@event.name} + +%p + Total Tickets: #{@ticket_request.total_tickets} + %br + - @ticket_request.active_sorted_addons.each do |tr_event_addon| + Event Addons: + = "#{tr_event_addon.name}: #{tr_event_addon.quantity}" %p If your request is approved, we will send you confirmation of the approved 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 290d85f3..edd87067 100644 --- a/app/views/ticket_requests/_table_ticket_request_statuses.html.haml +++ b/app/views/ticket_requests/_table_ticket_request_statuses.html.haml @@ -17,7 +17,7 @@ %tr %th.text-nowrap.bg-dark-subtle.text-left Tickets Status - %th.bg-dark-subtle.text-end.optional-medium Requests + %th.bg-dark-subtle.text-end Requests %th.bg-dark-subtle.text-end Tickets - if event.kid_ticket_price %th.bg-dark-subtle.text-end Kids Tix @@ -36,7 +36,7 @@ %tr.fs-6 %td.bg-success-subtle %span.text-nowrap Paid - %td.text-end.bg-success-subtle.optional-medium + %td.text-end.bg-success-subtle %span= stats[:completed][:requests] %td.text-end.bg-success-subtle %span= stats[:completed][:adults] @@ -60,7 +60,7 @@ %tr.fs-6 %td.text-nowrap.bg-warning Pending Approval - %td.text-end.bg-warning.optional-medium= stats[:pending][:requests] + %td.text-end.bg-warning= stats[:pending][:requests] %td.text-end.bg-warning= stats[:pending][:adults] - if event.kid_ticket_price %td.text-end.bg-warning= stats[:pending][:kids] @@ -77,7 +77,7 @@ %tr.fs-6 %td.text-nowrap.bg-warning-subtle Awaiting Payment - %td.text-end.bg-warning-subtle.optional-medium= stats[:awaiting_payment][:requests] + %td.text-end.bg-warning-subtle= stats[:awaiting_payment][:requests] %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] @@ -95,7 +95,7 @@ %td.bg-dark-subtle.text-start %strong Total - %td.bg-dark-subtle.text-end.optional-medium= stats[:total][:requests] + %td.bg-dark-subtle.text-end= stats[:total][:requests] %td.bg-dark-subtle.text-end= stats[:total][:adults] - if event.kid_ticket_price %td.bg-dark-subtle.text-end= stats[:total][:kids] diff --git a/app/views/ticket_requests/_table_ticket_requests.html.haml b/app/views/ticket_requests/_table_ticket_requests.html.haml index 3247a675..2befe395 100644 --- a/app/views/ticket_requests/_table_ticket_requests.html.haml +++ b/app/views/ticket_requests/_table_ticket_requests.html.haml @@ -8,17 +8,17 @@ %tr %th.bg-dark-subtle Name - if event.require_role - %th.bg-dark-subtle.optional-medium Role + %th.bg-dark-subtle Role %th.bg-dark-subtle Notes - %th.bg-dark-subtle.text-end.optional-medium Tickets + %th.bg-dark-subtle.text-end Tickets - if event.kid_ticket_price - %th.bg-dark-subtle.text-end.optional-medium Kids + %th.bg-dark-subtle.text-end Kids - if event.allow_donations - %th.bg-dark-subtle.text-end.optional-medium Donation + %th.bg-dark-subtle.text-end Donation %th.bg-dark-subtle.text-end Total - %th.bg-dark-subtle.text-end.optional-medium Date Requested + %th.bg-dark-subtle.text-end Date Requested %th.bg-dark-subtle.text-center Status - %th.bg-dark-subtle.text-center Payment + %th.bg-dark-subtle.text-center Payments %tbody.border-dark-subtle.border-2 @@ -31,7 +31,7 @@ -# If we role is required for the event, add the column for role - if event.require_role - %td.muted.align-content-center.optional-medium + %td.muted.align-content-center = TicketRequest::ROLES[ticket_request.role] %i.icon-comment.hover-tooltip{ title: ticket_request.role_explanation } @@ -52,13 +52,13 @@ = tooltip_box(ticket_request.admin_notes, title: "Admin Notes") do = image_tag('icons/comments-admin.png', width: 20, class: 'hover-tooltip') - %td.align-content-center.text-end.optional-medium= ticket_request.adults + %td.align-content-center.text-end= ticket_request.adults - if event.kid_ticket_price - %td.align-content-center.text-end.optional-medium= ticket_request.kids + %td.align-content-center.text-end= ticket_request.kids - if event.allow_donations - %td.align-content-center.text-end.optional-medium + %td.align-content-center.text-end = number_to_currency(ticket_request.donation, precision: 0) %td.align-content-center.text-end diff --git a/spec/controllers/ticket_requests_controller_spec.rb b/spec/controllers/ticket_requests_controller_spec.rb index b3e41285..9792cdd5 100644 --- a/spec/controllers/ticket_requests_controller_spec.rb +++ b/spec/controllers/ticket_requests_controller_spec.rb @@ -152,67 +152,65 @@ } end - describe 'without Ventable callbacks', :ventable_disabled do - describe 'ticket_request_params' do - subject { ticket_request_params } + describe 'ticket_request_params' do + subject { ticket_request_params } - it { is_expected.to be_a(Hash) } - it { is_expected.to include('event_id' => event.id) } - it { is_expected.not_to include('ticket_request' => ['status']) } - end + it { is_expected.to be_a(Hash) } + it { is_expected.to include('event_id' => event.id) } + it { is_expected.not_to include('ticket_request' => ['status']) } + end - context 'when event ticket sales are closed' do - let(:viewer) { create(:user) } + context 'when event ticket sales are closed' do + let(:viewer) { create(:user) } - it 'has no error message before the request' do - Timecop.freeze(event.end_time + 1.hour) do - make_request[] - expect(response).to redirect_to(attend_event_path(event)) - expect(flash.now[:error]).to_not be_nil - end + it 'has no error message before the request' do + Timecop.freeze(event.end_time + 1.hour) do + make_request[] + expect(response).to redirect_to(attend_event_path(event)) + expect(flash.now[:error]).to_not be_nil end end + end - context 'when viewer already signed in' do - subject { make_request.call } + context 'when viewer already signed in' do + subject { make_request.call } - let(:viewer) { user } + let(:viewer) { user } - before { TicketRequest.where(user_id: viewer.id).destroy_all } + before { TicketRequest.where(user_id: viewer.id).destroy_all } - describe '#create HTTP status' do - it { succeeds } + describe '#create HTTP status' do + it { succeeds } - it 'has no errors' do - expect(flash[:error]).to be_nil - end + it 'has no errors' do + expect(flash[:error]).to be_nil end + end - describe 'database state' do - subject(:response) { make_request[] } + describe 'database state' do + subject(:response) { make_request[] } - it 'creates a ticket request' do - expect { subject }.to(change(TicketRequest, :count)) - end + it 'creates a ticket request' do + expect { subject }.to(change(TicketRequest, :count)) + end - it 'assigned the ticket request to the viewer' do - expect { subject }.to change { viewer.ticket_requests.count }.by(1) - end + it 'assigned the ticket request to the viewer' do + expect { subject }.to change { viewer.ticket_requests.count }.by(1) end end + end - context 'when viewer is not signed in' do - before { make_request.call } + context 'when viewer is not signed in' do + before { make_request.call } - let(:viewer) { nil } + let(:viewer) { nil } - it { expect(response).to have_http_status(:redirect) } + it { expect(response).to have_http_status(:redirect) } - it { expect(flash.now[:error]).to be_nil } + it { expect(flash.now[:error]).to be_nil } - it 'not log the user in' do - expect(controller.current_user).to be_nil - end + it 'not log the user in' do + expect(controller.current_user).to be_nil end end end diff --git a/spec/mailers/ticket_request_mailer_spec.rb b/spec/mailers/ticket_request_mailer_spec.rb index ee13eea4..2148c5a3 100644 --- a/spec/mailers/ticket_request_mailer_spec.rb +++ b/spec/mailers/ticket_request_mailer_spec.rb @@ -11,7 +11,19 @@ describe '#request_received' do subject(:mail) { described_class.request_received(ticket_request) } - its(:subject) { is_expected.to eql "#{event.name} ticket request confirmation" } + its(:subject) { is_expected.to eql "#{event.name} ticket request received!" } + + its(:to) { is_expected.to eql [user.email] } + + its('body.encoded') { is_expected.to match(user.first_name) } + + its('body.encoded') { is_expected.to match(event.name) } + end + + describe '#request_confirmed' do + subject(:mail) { described_class.request_confirmed(ticket_request) } + + its(:subject) { is_expected.to eql "#{event.name} ticket confirmation!" } its(:to) { is_expected.to eql [user.email] } @@ -42,7 +54,7 @@ context 'when the ticket request is not free' do let(:price) { 10 } - its(:body) { is_expected.to match('purchase') } + its(:body) { is_expected.to match('buy') } end end end