diff --git a/app/controllers/ticket_purchases_controller.rb b/app/controllers/ticket_purchases_controller.rb index f15fc993..a53a3cf5 100644 --- a/app/controllers/ticket_purchases_controller.rb +++ b/app/controllers/ticket_purchases_controller.rb @@ -19,7 +19,7 @@ class TicketPurchasesController < ApplicationController error: 'Please get at least one ticket to continue.' end else - redirect_to conference_conference_registration_path(@conference.short_title), + redirect_to conference_tickets_path(@conference.short_title), error: "Oops, something went wrong with your purchase! #{message}" end end diff --git a/app/models/ticket_purchase.rb b/app/models/ticket_purchase.rb index a2ed2747..97fa9957 100644 --- a/app/models/ticket_purchase.rb +++ b/app/models/ticket_purchase.rb @@ -5,7 +5,8 @@ class TicketPurchase < ActiveRecord::Base belongs_to :payment validates :ticket_id, :user_id, :conference_id, :quantity, presence: true - + validate :one_registration_ticket_per_user + validate :registration_ticket_already_purchased, on: :create validates :quantity, numericality: { greater_than: 0 } delegate :title, to: :ticket @@ -25,18 +26,21 @@ class TicketPurchase < ActiveRecord::Base def self.purchase(conference, user, purchases) errors = [] - ActiveRecord::Base.transaction do - conference.tickets.each do |ticket| - quantity = purchases[ticket.id.to_s].to_i - # if the user bought the ticket and is still unpaid, just update the quantity - purchase = if ticket.bought?(user) && ticket.unpaid?(user) - update_quantity(conference, quantity, ticket, user) - else - purchase_ticket(conference, quantity, ticket, user) - end - - if purchase && !purchase.save - errors.push(purchase.errors.full_messages) + if count_purchased_registration_tickets(conference, purchases) > 1 + errors.push('You cannot buy more than one registration tickets.') + else + ActiveRecord::Base.transaction do + conference.tickets.each do |ticket| + quantity = purchases[ticket.id.to_s].to_i + # if the user bought the ticket and is still unpaid, just update the quantity + purchase = if ticket.bought?(user) && ticket.unpaid?(user) + update_quantity(conference, quantity, ticket, user) + else + purchase_ticket(conference, quantity, ticket, user) + end + if purchase && !purchase.save + errors.push(purchase.errors.full_messages) + end end end end @@ -71,6 +75,18 @@ class TicketPurchase < ActiveRecord::Base end Mailbot.ticket_confirmation_mail(self).deliver_later end + + def one_registration_ticket_per_user + if ticket.try(:registration_ticket?) && quantity != 1 + errors.add(:quantity, 'cannot be greater than one for registration tickets.') + end + end + + def registration_ticket_already_purchased + if ticket.try(:registration_ticket?) && user.tickets.for_registration(conference).present? + errors.add(:quantity, 'cannot be greater than one for registration tickets.') + end + end end private @@ -79,3 +95,9 @@ def set_week self.week = created_at.strftime('%W') save! end + +def count_purchased_registration_tickets(conference, purchases) + conference.tickets.for_registration.inject(0) do |sum, registration_ticket| + sum + purchases[registration_ticket.id.to_s].to_i + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 793db609..ccdb488d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -51,7 +51,11 @@ class User < ActiveRecord::Base has_many :events_registrations, through: :registrations has_many :ticket_purchases, dependent: :destroy has_many :payments, dependent: :destroy - has_many :tickets, through: :ticket_purchases, source: :ticket + has_many :tickets, through: :ticket_purchases, source: :ticket do + def for_registration conference + where(conference: conference, registration_ticket: true).first + end + end has_many :votes, dependent: :destroy has_many :voted_events, through: :votes, source: :events has_many :subscriptions, dependent: :destroy diff --git a/app/views/conference_registrations/show.html.haml b/app/views/conference_registrations/show.html.haml index c510a263..83d6d89c 100644 --- a/app/views/conference_registrations/show.html.haml +++ b/app/views/conference_registrations/show.html.haml @@ -109,7 +109,7 @@ You haven't bought any tickets. = link_to 'Please get some tickets to support us!', conference_tickets_path(@conference.short_title) %p - (Your participation won't be valid without getting a ticket) + (Your participation won't be valid without getting a registration ticket) .row .col-md-12 diff --git a/app/views/tickets/_ticket.html.haml b/app/views/tickets/_ticket.html.haml index e3985773..8f5fc82b 100644 --- a/app/views/tickets/_ticket.html.haml +++ b/app/views/tickets/_ticket.html.haml @@ -1,5 +1,5 @@ %tr - %td.col-sm-8.col-md-6 + %td.col-sm-8.col-md-4 .media .media-body %h4.media-heading @@ -7,9 +7,14 @@ %h5.media-heading - unless ticket.description.blank? = markdown(ticket.description) + %td.col-sm-1.col-md-2.text-center + = ticket.registration_ticket? ? 'Yes' : 'No' %td.col-sm-1.col-md-1 - = text_field_tag("tickets[][#{ticket.id}]", 0, - type: 'number', min: 0, class: "form-control quantity", 'data-id' => ticket.id) + - options = { type: 'number', min: 0, class: "form-control quantity", 'data-id' => ticket.id } + - if ticket.registration_ticket? + - options[:max] = 1 + - options[:disabled] = current_user.tickets.for_registration(ticket.conference).present? + = text_field_tag("tickets[][#{ticket.id}]", 0, options) %td.col-sm-1.col-md-1.text-center = ticket.price.symbol %span{id: "price_#{ticket.id}"} diff --git a/app/views/tickets/index.html.haml b/app/views/tickets/index.html.haml index dc67f529..cba13ea5 100644 --- a/app/views/tickets/index.html.haml +++ b/app/views/tickets/index.html.haml @@ -14,6 +14,7 @@ %thead %tr %th Ticket + %th Registration Ticket %th Quantity %th Price %th Total @@ -21,6 +22,7 @@ - @conference.tickets.each do |ticket| = render partial: 'ticket', f: f, locals: {ticket: ticket} %tr + %td %td %td %td.col-sm-1.col-md-1.text-center @@ -46,4 +48,4 @@ .col-md-13 %p.text-muted.text-center %small - * Getting a ticket is mandatory. Your participation will not be valid until you get a ticket. + * Getting a registration ticket is mandatory. Your participation will not be valid until you get a registration ticket. diff --git a/spec/features/ticket_purchases_spec.rb b/spec/features/ticket_purchases_spec.rb index 958ae645..c76b84a6 100644 --- a/spec/features/ticket_purchases_spec.rb +++ b/spec/features/ticket_purchases_spec.rb @@ -3,7 +3,9 @@ require 'spec_helper' feature Registration do let!(:ticket) { create(:ticket) } 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!(:first_registration_ticket) { create(:registration_ticket, price_cents: 0) } + let!(:second_registration_ticket) { create(:registration_ticket, price_cents: 0) } + let!(:conference) { create(:conference, title: 'ExampleCon', tickets: [ticket, free_ticket, first_registration_ticket, second_registration_ticket], registration_period: create(:registration_period, start_date: 3.days.ago)) } let!(:participant) { create(:user) } context 'as a participant' do @@ -106,6 +108,38 @@ feature Registration do expect(purchase.quantity).to eq(5) expect(purchase.paid).to be true end + + scenario 'purchases more than one registration tickets of a single type' 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__#{first_registration_ticket.id}", with: '5' + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + + click_button 'Continue' + + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + end + + scenario 'purchases one registration ticket of a different types' 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__#{first_registration_ticket.id}", with: '1' + fill_in "tickets__#{second_registration_ticket.id}", with: '1' + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + + click_button 'Continue' + + expect(flash).to eq('Oops, something went wrong with your purchase! You cannot buy more than one registration tickets.') + expect(current_path).to eq(conference_tickets_path(conference.short_title)) + end end context 'who is registered' do diff --git a/spec/models/ticket_purchase_spec.rb b/spec/models/ticket_purchase_spec.rb index 3ef9a861..bfca5efc 100644 --- a/spec/models/ticket_purchase_spec.rb +++ b/spec/models/ticket_purchase_spec.rb @@ -34,6 +34,22 @@ describe TicketPurchase do it 'is valid with a quantity greater than zero' do should allow_value(1).for(:quantity) end + + describe 'one_registration_ticket_per_user' do + let(:registration_ticket) { create(:registration_ticket) } + let(:ticket_purchase) { build(:ticket_purchase, ticket: registration_ticket, quantity: 1) } + + it 'it is valid, if quantity for registration tickets is less than or equal to one' do + expect(ticket_purchase.valid?).to eq true + end + + it 'it is not valid, if quantity for registration tickets is greater than to one' do + ticket_purchase.quantity = 4 + + expect(ticket_purchase.valid?).to eq false + expect(ticket_purchase.errors[:quantity]).to eq ['cannot be greater than one for registration tickets.'] + end + end end describe 'self#purchase' do