Merge pull request #1118 from rishabhs95/free-ticket

ability to create and purchase free tickets
This commit is contained in:
Hernán Schmidt 2017-01-31 14:54:18 +01:00 committed by GitHub
commit a4ef10cf1b
9 changed files with 88 additions and 24 deletions

View file

@ -10,6 +10,9 @@ class TicketPurchasesController < ApplicationController
if current_user.ticket_purchases.by_conference(@conference).unpaid.any? if current_user.ticket_purchases.by_conference(@conference).unpaid.any?
redirect_to new_conference_payment_path, redirect_to new_conference_payment_path,
notice: 'Please pay here to get tickets.' notice: 'Please pay here to get tickets.'
elsif current_user.ticket_purchases.by_conference(@conference).paid.any?
redirect_to conference_conference_registration_path(@conference.short_title),
notice: 'You have free tickets for the conference.'
else else
redirect_to conference_tickets_path(@conference.short_title), redirect_to conference_tickets_path(@conference.short_title),
error: 'Please get at least one ticket to continue.' error: 'Please get at least one ticket to continue.'

View file

@ -1,3 +1,4 @@
# rubocop:disable Metrics/ClassLength
## ##
# This class represents a conference # This class represents a conference
class Conference < ActiveRecord::Base class Conference < ActiveRecord::Base
@ -64,6 +65,8 @@ class Conference < ActiveRecord::Base
before_create :add_color before_create :add_color
before_create :create_email_settings before_create :create_email_settings
after_create :create_free_ticket
def date_range_string def date_range_string
startstr = 'Unknown - ' startstr = 'Unknown - '
endstr = 'Unknown' endstr = 'Unknown'
@ -647,6 +650,14 @@ class Conference < ActiveRecord::Base
create_roles create_roles
end end
##
# Creates free ticket for the conference
# after the conference has been successfully created
# Will create 1 new record for 'free' ticket
def create_free_ticket
tickets.where(title: 'Free Access', price_cents: 0).first_or_create!(description: 'Get free access tickets for the conference.')
end
## ##
# Creates the roles of the conference # Creates the roles of the conference
# after the conference has been successfully created # after the conference has been successfully created
@ -1053,3 +1064,4 @@ class Conference < ActiveRecord::Base
result result
end end
end end
# rubocop:enable Metrics/ClassLength

View file

@ -13,7 +13,7 @@ class Ticket < ActiveRecord::Base
validates :price_cents, :price_currency, :title, presence: true validates :price_cents, :price_currency, :title, presence: true
validates_numericality_of :price_cents, greater_than: 0 validates_numericality_of :price_cents, greater_than_or_equal_to: 0
def bought?(user) def bought?(user)
buyers.include?(user) buyers.include?(user)

View file

@ -23,7 +23,7 @@ class TicketPurchase < ActiveRecord::Base
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
conference.tickets.each do |ticket| conference.tickets.each do |ticket|
quantity = purchases[ticket.id.to_s].to_i quantity = purchases[ticket.id.to_s].to_i
# if the user bought the ticket, just update the quantity # if the user bought the ticket and is still unpaid, just update the quantity
if ticket.bought?(user) && ticket.unpaid?(user) if ticket.bought?(user) && ticket.unpaid?(user)
purchase = update_quantity(conference, quantity, ticket, user) purchase = update_quantity(conference, quantity, ticket, user)
else else
@ -39,10 +39,13 @@ class TicketPurchase < ActiveRecord::Base
end end
def self.purchase_ticket(conference, quantity, ticket, user) def self.purchase_ticket(conference, quantity, ticket, user)
purchase = new(ticket_id: ticket.id, if quantity > 0
conference_id: conference.id, purchase = new(ticket_id: ticket.id,
user_id: user.id, conference_id: conference.id,
quantity: quantity) if quantity > 0 user_id: user.id,
quantity: quantity,
paid: ticket.price_cents.zero?)
end
purchase purchase
end end

View file

@ -2,7 +2,8 @@ require 'spec_helper'
feature Registration do feature Registration do
let!(:ticket) { create(:ticket) } let!(:ticket) { create(:ticket) }
let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) } let!(:free_ticket) { create(:ticket, price_cents: 0) }
let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket, free_ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) }
let!(:participant) { create(:user) } let!(:participant) { create(:user) }
context 'as a participant' do context 'as a participant' do
@ -87,6 +88,26 @@ feature Registration do
expect(flash).to eq('Your card was declined. Please try again with correct credentials.') expect(flash).to eq('Your card was declined. Please try again with correct credentials.')
end end
end end
scenario 'purchases free tickets' do
visit root_path
click_link 'Register'
expect(current_path).to eq(new_conference_conference_registration_path(conference.short_title))
click_button 'Register'
fill_in "tickets__#{free_ticket.id}", with: '5'
expect(current_path).to eq(conference_tickets_path(conference.short_title))
click_button 'Continue'
expect(current_path).to eq(conference_conference_registration_path(conference.short_title))
purchase = TicketPurchase.where(user_id: participant.id, ticket_id: free_ticket.id).first
expect(purchase.quantity).to eq(5)
expect(purchase.paid).to be true
expect(page.has_content?("5 #{free_ticket.title} Tickets for $ 0")).to be true
end
end end
context 'who is registered' do context 'who is registered' do

View file

@ -24,7 +24,7 @@ feature Ticket do
click_button 'Create Ticket' click_button 'Create Ticket'
expect(flash).to eq('Ticket successfully created.') expect(flash).to eq('Ticket successfully created.')
expect(Ticket.count).to eq(1) expect(Ticket.count).to eq(2)
end end
scenario 'add a invalid ticket', feature: true, js: true do scenario 'add a invalid ticket', feature: true, js: true do
@ -35,8 +35,8 @@ feature Ticket do
fill_in 'ticket_price', with: '-1' fill_in 'ticket_price', with: '-1'
click_button 'Create Ticket' click_button 'Create Ticket'
expect(flash).to eq("Creating Ticket failed: Title can't be blank. Price cents must be greater than 0.") expect(flash).to eq("Creating Ticket failed: Title can't be blank. Price cents must be greater than or equal to 0.")
expect(Ticket.count).to eq(0) expect(Ticket.count).to eq(1)
end end
context 'Ticket already created' do context 'Ticket already created' do
@ -44,9 +44,9 @@ feature Ticket do
scenario 'edit valid ticket', feature: true, js: true do scenario 'edit valid ticket', feature: true, js: true do
visit admin_conference_tickets_path(conference.short_title) visit admin_conference_tickets_path(conference.short_title)
click_link 'Edit' click_link('Edit', href: edit_admin_conference_ticket_path(conference.short_title, ticket.id))
fill_in 'ticket_title', with: 'Free Ticket' fill_in 'ticket_title', with: 'Event Ticket'
fill_in 'ticket_price', with: '50' fill_in 'ticket_price', with: '50'
click_button 'Update Ticket' click_button 'Update Ticket'
@ -54,14 +54,14 @@ feature Ticket do
ticket.reload ticket.reload
# It's necessary to multiply by 100 because the price is in cents # It's necessary to multiply by 100 because the price is in cents
expect(ticket.price).to eq(Money.new(50 * 100, 'USD')) expect(ticket.price).to eq(Money.new(50 * 100, 'USD'))
expect(ticket.title).to eq('Free Ticket') expect(ticket.title).to eq('Event Ticket')
expect(flash).to eq('Ticket successfully updated.') expect(flash).to eq('Ticket successfully updated.')
expect(Ticket.count).to eq(1) expect(Ticket.count).to eq(2)
end end
scenario 'edit invalid ticket', feature: true, js: true do scenario 'edit invalid ticket', feature: true, js: true do
visit admin_conference_tickets_path(conference.short_title) visit admin_conference_tickets_path(conference.short_title)
click_link 'Edit' click_link('Edit', href: edit_admin_conference_ticket_path(conference.short_title, ticket.id))
fill_in 'ticket_title', with: '' fill_in 'ticket_title', with: ''
fill_in 'ticket_price', with: '-5' fill_in 'ticket_price', with: '-5'
@ -72,16 +72,16 @@ feature Ticket do
# It's necessary to multiply by 100 because the price is in cents # It's necessary to multiply by 100 because the price is in cents
expect(ticket.price).to eq(Money.new(100 * 100, 'USD')) expect(ticket.price).to eq(Money.new(100 * 100, 'USD'))
expect(ticket.title).to eq('Business Ticket') expect(ticket.title).to eq('Business Ticket')
expect(flash).to eq("Ticket update failed: Title can't be blank. Price cents must be greater than 0.") expect(flash).to eq("Ticket update failed: Title can't be blank. Price cents must be greater than or equal to 0.")
expect(Ticket.count).to eq(1) expect(Ticket.count).to eq(2)
end end
scenario 'delete ticket', feature: true, js: true do scenario 'delete ticket', feature: true, js: true do
visit admin_conference_tickets_path(conference.short_title) visit admin_conference_tickets_path(conference.short_title)
click_link 'Delete' click_link('Delete', href: admin_conference_ticket_path(conference.short_title, ticket.id))
expect(flash).to eq('Ticket successfully destroyed.') expect(flash).to eq('Ticket successfully destroyed.')
expect(Ticket.count).to eq(0) expect(Ticket.count).to eq(1)
end end
end end
end end

View file

@ -1583,4 +1583,15 @@ describe Conference do
end end
end end
end end
describe 'after_create' do
let(:conference) { Conference.new(title: 'ABC', short_title: 'XYZ', start_date: Date.today, end_date: Date.today + 10, timezone: 'GMT') }
it 'calls back to create free ticket' do
conference.save
conference.run_callbacks :create
free_ticket = conference.tickets.first
expect(free_ticket.price_cents).to eq(0)
end
end
end end

View file

@ -41,7 +41,21 @@ describe TicketPurchase do
let!(:participant) { create(:user) } let!(:participant) { create(:user) }
let!(:ticket_1) { create(:ticket) } let!(:ticket_1) { create(:ticket) }
let!(:ticket_2) { create(:ticket) } let!(:ticket_2) { create(:ticket) }
let!(:conference) { create(:conference, tickets: [ticket_1, ticket_2]) } let!(:free_ticket) { create(:ticket, price_cents: 0) }
let!(:conference) { create(:conference, tickets: [ticket_1, ticket_2, free_ticket]) }
it 'creates purchase to free ticket' do
tickets = { free_ticket.id.to_s => '10' }
message = TicketPurchase.purchase(conference, participant, tickets)
purchase = TicketPurchase.where(conference_id: conference.id,
user_id: participant.id,
ticket_id: free_ticket.id).first
expect(TicketPurchase.count).to eq(1)
expect(purchase.quantity).to eq(10)
expect(message.blank?).to be true
end
it 'creates a purchase for one ticket' do it 'creates a purchase for one ticket' do
tickets = { ticket_1.id.to_s => '1' } tickets = { ticket_1.id.to_s => '1' }

View file

@ -22,14 +22,14 @@ describe Ticket do
should validate_presence_of(:price_currency) should validate_presence_of(:price_currency)
end end
it 'is not valid with a price_cents equals zero' do
should_not allow_value(0).for(:price_cents)
end
it 'is not valid with a price_cents smaller than zero' do it 'is not valid with a price_cents smaller than zero' do
should_not allow_value(-1).for(:price_cents) should_not allow_value(-1).for(:price_cents)
end end
it 'is valid with a price_cents equals zero' do
should allow_value(0).for(:price_cents)
end
it 'is valid with a price_cents greater than zero' do it 'is valid with a price_cents greater than zero' do
should allow_value(1).for(:price_cents) should allow_value(1).for(:price_cents)
end end