Skip to content

Commit

Permalink
Merge pull request #372 from cs169/187376318-ticket-purchases-curr-co…
Browse files Browse the repository at this point in the history
…nversion

187376318 ticket purchases curr conversion
  • Loading branch information
cycomachead authored Jul 20, 2024
2 parents fdab814 + bfafbd5 commit acb36a5
Show file tree
Hide file tree
Showing 15 changed files with 156 additions and 96 deletions.
15 changes: 10 additions & 5 deletions app/controllers/conference_registrations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,16 @@ def new
end

def show
@total_price = Ticket.total_price_user(@conference, current_user, paid: true)
@tickets = current_user.ticket_purchases.by_conference(@conference).paid
@total_price_per_ticket = @tickets.group(:ticket_id).sum('amount_paid * quantity')
@ticket_payments = @tickets.group_by(&:ticket_id)
@total_quantity = @tickets.group(:ticket_id).sum(:quantity)
@purchases = current_user.ticket_purchases.by_conference(@conference).paid
summed_per_ticket_per_currency = @purchases.group(:ticket_id, :currency).sum('amount_paid_cents * quantity')
@total_price_per_ticket_per_currency = summed_per_ticket_per_currency.each_with_object({}) do |((ticket_id, currency), amount), hash|
hash[[ticket_id, currency]] = Money.new(amount, currency)
end
@total_quantity = @purchases.group(:ticket_id, :currency).sum(:quantity)
sum_total_currency = @purchases.group(:currency).sum('amount_paid_cents * quantity')
@total_price_per_currency = sum_total_currency.each_with_object({}) do |(currency, amount), hash|
hash[currency] = Money.new(amount, currency)
end
end

def edit; end
Expand Down
4 changes: 0 additions & 4 deletions app/controllers/payments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@ def new
@has_registration_ticket = params[:has_registration_ticket]
@unpaid_ticket_purchases = current_user.ticket_purchases.unpaid.by_conference(@conference)

@converted_prices = {}
@unpaid_ticket_purchases.each do |ticket_purchase|
@converted_prices[ticket_purchase.id] = ticket_purchase.amount_paid
end
@currency = selected_currency
end

Expand Down
7 changes: 1 addition & 6 deletions app/models/ticket.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,16 +80,11 @@ def self.total_price(conference, user, paid: false)
result || Money.new(0, 'USD')
end

def self.total_price_user(conference, user, paid: false)
tickets = TicketPurchase.where(conference: conference, user: user, paid: paid)
tickets.inject(0) { |sum, ticket| sum + (ticket.amount_paid * ticket.quantity) }
end

def tickets_turnover_total(id)
ticket = Ticket.find(id)
return Money.new(0, 'USD') unless ticket

sum = ticket.ticket_purchases.paid.total
sum = ticket.price_cents * ticket.ticket_purchases.paid.total_quantity
Money.new(sum, ticket.price_currency)
end

Expand Down
44 changes: 26 additions & 18 deletions app/models/ticket_purchase.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
#
# Table name: ticket_purchases
#
# id :bigint not null, primary key
# amount_paid :float default(0.0)
# currency :string
# paid :boolean default(FALSE)
# quantity :integer default(1)
# week :integer
# created_at :datetime
# conference_id :integer
# payment_id :integer
# ticket_id :integer
# user_id :integer
# id :bigint not null, primary key
# amount_paid :float default(0.0)
# amount_paid_cents :integer default(0)
# currency :string
# paid :boolean default(FALSE)
# quantity :integer default(1)
# week :integer
# created_at :datetime
# conference_id :integer
# payment_id :integer
# ticket_id :integer
# user_id :integer
#

class TicketPurchase < ApplicationRecord
Expand All @@ -30,12 +31,13 @@ class TicketPurchase < ApplicationRecord

delegate :title, to: :ticket
delegate :description, to: :ticket
delegate :price, to: :ticket
delegate :price_cents, to: :ticket
delegate :price_currency, to: :ticket

has_many :physical_tickets

monetize :amount_paid_cents, with_model_currency: :currency, as: 'purchase_price'

scope :paid, -> { where(paid: true) }
scope :unpaid, -> { where(paid: false) }
scope :by_conference, ->(conference) { where(conference_id: conference.id) }
Expand Down Expand Up @@ -71,12 +73,13 @@ def self.purchase_ticket(conference, quantity, ticket, user, currency)
purchase.pay(nil)
end
if quantity > 0
purchase = new(ticket_id: ticket.id,
conference_id: conference.id,
user_id: user.id,
quantity: quantity,
amount_paid: converted_amount,
currency: currency)
purchase = new(ticket_id: ticket.id,
conference_id: conference.id,
user_id: user.id,
quantity: quantity,
amount_paid: converted_amount.to_f,
amount_paid_cents: converted_amount.fractional,
currency: currency)
purchase.pay(nil) if converted_amount.zero?
end
purchase
Expand All @@ -97,6 +100,11 @@ def self.total
sum('amount_paid * quantity')
end

# Total quantity
def self.total_quantity
sum('quantity')
end

def pay(payment)
update(paid: true, payment: payment)
PhysicalTicket.transaction do
Expand Down
3 changes: 2 additions & 1 deletion app/views/admin/physical_tickets/_physical_ticket.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
%td= physical_ticket.ticket.title
%td= physical_ticket.ticket.registration_ticket? ? 'Yes' : 'No'
%td= physical_ticket.user&.email
%td= humanized_money_with_symbol physical_ticket.ticket_purchase.amount_paid
%td= humanized_money_with_symbol(physical_ticket.ticket_purchase.purchase_price)
%td= physical_ticket.ticket_purchase.currency || 'USD'
%td
- if physical_ticket.ticket_scannings.present?
%span Checked in:
Expand Down
1 change: 1 addition & 0 deletions app/views/admin/physical_tickets/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
%th Registration?
%th User
%th Paid
%th Currency
%th Attedance
%th Actions
%tbody
Expand Down
44 changes: 22 additions & 22 deletions app/views/conference_registrations/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -86,27 +86,27 @@
%i.fa-solid.fa-square-dashed.fa-stack-2x
%i.fa-solid.fa-ticket.fa-stack-1x
Tickets
- if @tickets.any?
Total Purchased:
= "(#{@tickets.first.price.symbol}#{humanized_money @total_price})"
%ul
.col-md-12
- @ticket_payments.each_pair do |ticket_id, tickets|
%li
= @total_quantity[ticket_id]
= tickets.first.title
= word_pluralize(@total_quantity[ticket_id], 'Ticket')
for
= tickets.first.price.symbol
= humanized_money @total_price_per_ticket[ticket_id]
%br
.btn-group{ role: 'group' }
= link_to 'View all tickets',
conference_physical_tickets_path(@conference.short_title),
class: 'btn btn-success'
= link_to 'Get more tickets',
conference_tickets_path(@conference.short_title),
class: 'btn btn-default'
- if @purchases.any?
.col-md-12
- @total_price_per_currency.each do |currency, total_price|
%h4
Total Purchased (#{currency}):
= humanized_money_with_symbol(total_price)
%ul
- @total_price_per_ticket_per_currency.select { |(id, curr)| curr == currency }.each do |(ticket_id, curr), total_amount|
- purchase = @purchases.find { |p| p.ticket_id == ticket_id && p.currency == curr }
%li
- title = purchase.title.titleize.gsub(/(?i)\bticket\b/, 'Tickets')
- title = title.include?('Tickets') ? title : "#{title} Tickets"
= "#{@total_quantity[[ticket_id, currency]]} #{title} for "
= humanized_money_with_symbol(total_amount)
.btn-group{ role: 'group' }
= link_to 'View all tickets',
conference_physical_tickets_path(@conference.short_title),
class: 'btn btn-success'
= link_to 'Get more tickets',
conference_tickets_path(@conference.short_title),
class: 'btn btn-default'
- else
%p
You haven't bought any tickets.
Expand All @@ -125,7 +125,7 @@
- if @registration
.btn-group-vertical.pull-right
= link_to 'Edit your Registration', edit_conference_conference_registration_path(@conference.short_title), class: 'btn btn-success', disabled: @conference.end_date < Date.today
- if @tickets.any?
- if @purchases.any?
= link_to 'Unregister', conference_conference_registration_path(@conference.short_title), method: :delete, class: 'btn btn-danger btn-xs',
data: { confirm: "Your ticket purchases won't be refunded. Are you sure you want to unregister?" }, disabled: @conference.end_date < Date.today
- else
Expand Down
4 changes: 2 additions & 2 deletions app/views/payments/_payment.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
%td
= ticket.quantity
%td
= humanized_money_with_symbol @converted_prices[ticket.id]
= humanized_money_with_symbol ticket.purchase_price
%td
= humanized_money_with_symbol (@converted_prices[ticket.id] * ticket.quantity)
= humanized_money_with_symbol ticket.purchase_price * ticket.quantity
= form_tag conference_payments_path(@conference.short_title, :has_registration_ticket => @has_registration_ticket) do
%script.stripe-button{ src: "https://checkout.stripe.com/checkout.js",
data: { amount: @total_amount_to_pay.cents,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class SetCurrencyForNullTicketPurchaseCurrency < ActiveRecord::Migration[7.0]
def up
TicketPurchase.where(currency: nil).update_all(currency: 'USD')
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
class AddAmountPaidCentsToTicketPurchases < ActiveRecord::Migration[7.0]
def up
add_column :ticket_purchases, :amount_paid_cents, :integer, default: 0

TicketPurchase.reset_column_information

TicketPurchase.find_each do |purchase|
converted_amount = CurrencyConversion.convert_currency(
purchase.conference,
purchase.price,
purchase.price_currency,
purchase.currency
)

purchase.update_column(:amount_paid_cents, converted_amount.fractional)
end
end

def down
# Remove the amount_paid_cents column if you roll back this migration
remove_column :ticket_purchases, :amount_paid_cents
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[7.0].define(version: 2024_03_18_164346) do
ActiveRecord::Schema[7.0].define(version: 2024_04_22_200831) do
# These are extensions that must be enabled in order to support this database
enable_extension "pg_stat_statements"
enable_extension "plpgsql"
Expand Down Expand Up @@ -546,6 +546,7 @@
t.integer "week"
t.float "amount_paid", default: 0.0
t.string "currency"
t.integer "amount_paid_cents", default: 0
end

create_table "ticket_scannings", force: :cascade do |t|
Expand Down
35 changes: 24 additions & 11 deletions spec/controllers/conference_registration_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -265,28 +265,41 @@
end
end

context 'user has purchased a ticket' do
context 'user has not purchased any ticket' do
before do
@ticket = create(:ticket, conference: conference)
@purchased_ticket = create(:ticket_purchase, conference: conference,
user: user,
ticket: @ticket)
get :show, params: { conference_id: conference.short_title }
end

it 'does not assign price of purchased tickets to total_price and purchased tickets to tickets without payment' do
expect(assigns(:total_price)).to eq 0
it 'assigns an empty array to tickets variables' do
expect(assigns(:purchases)).to match_array []
end
end

context 'user has not purchased any ticket' do
context 'when user has purchased tickets' do
let!(:purchase) { create(:ticket_purchase, user: user, conference: conference, quantity: 2, amount_paid_cents: 10_000, currency: 'USD', paid: true, ticket_id: 1) }
let!(:purchase_not_paid) { create(:ticket_purchase, user: user, conference: conference, quantity: 2, amount_paid_cents: 10_000, currency: 'USD') }
let!(:purchase_diff_id) { create(:ticket_purchase, user: user, conference: conference, quantity: 1, amount_paid_cents: 10_000, currency: 'USD', paid: true, ticket_id: 2) }
let!(:purchase_diff_curr) { create(:ticket_purchase, user: user, conference: conference, quantity: 1, amount_paid_cents: 10_000, currency: 'CAD', paid: true, ticket_id: 1) }

before do
sign_in user
get :show, params: { conference_id: conference.short_title }
end

it 'assigns 0 dollars to total_price and empty array to tickets variables' do
expect(assigns(:total_price)).to eq 0
expect(assigns(:tickets)).to match_array []
it 'assigns @purchases correctly' do
expect(assigns(:purchases)).to contain_exactly(purchase, purchase_diff_id, purchase_diff_curr)
end

it 'assigns @total_price_per_ticket_per_currency correctly' do
expect(assigns(:total_price_per_ticket_per_currency)).to eq({ [purchase.ticket_id, 'USD'] => Money.new(20_000, 'USD'), [purchase_diff_id.ticket_id, 'USD'] => Money.new(10_000, 'USD'), [purchase_diff_curr.ticket_id, 'CAD'] => Money.new(10_000, 'CAD') })
end

it 'assigns @total_quantity correctly' do
expect(assigns(:total_quantity)).to eq({ [purchase.ticket_id, 'USD'] => 2, [purchase_diff_id.ticket_id, 'USD'] => 1, [purchase_diff_curr.ticket_id, 'CAD'] => 1 })
end

it 'assigns @total_price_per_currency correctly' do
expect(assigns(:total_price_per_currency)).to eq({ 'USD' => Money.new(30_000, 'USD'), 'CAD' => Money.new(10_000, 'CAD') })
end
end
end
Expand Down
23 changes: 12 additions & 11 deletions spec/factories/ticket_purchases.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
#
# Table name: ticket_purchases
#
# id :bigint not null, primary key
# amount_paid :float default(0.0)
# currency :string
# paid :boolean default(FALSE)
# quantity :integer default(1)
# week :integer
# created_at :datetime
# conference_id :integer
# payment_id :integer
# ticket_id :integer
# user_id :integer
# id :bigint not null, primary key
# amount_paid :float default(0.0)
# amount_paid_cents :integer default(0)
# currency :string
# paid :boolean default(FALSE)
# quantity :integer default(1)
# week :integer
# created_at :datetime
# conference_id :integer
# payment_id :integer
# ticket_id :integer
# user_id :integer
#
FactoryBot.define do
factory :ticket_purchase do
Expand Down
33 changes: 22 additions & 11 deletions spec/models/ticket_purchase_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@
#
# Table name: ticket_purchases
#
# id :bigint not null, primary key
# amount_paid :float default(0.0)
# currency :string
# paid :boolean default(FALSE)
# quantity :integer default(1)
# week :integer
# created_at :datetime
# conference_id :integer
# payment_id :integer
# ticket_id :integer
# user_id :integer
# id :bigint not null, primary key
# amount_paid :float default(0.0)
# amount_paid_cents :integer default(0)
# currency :string
# paid :boolean default(FALSE)
# quantity :integer default(1)
# week :integer
# created_at :datetime
# conference_id :integer
# payment_id :integer
# ticket_id :integer
# user_id :integer
#
require 'spec_helper'

Expand Down Expand Up @@ -67,6 +68,16 @@
end
end

describe 'monetization' do
let!(:purchase) { create(:ticket_purchase, amount_paid_cents: 1000, currency: 'USD') }

it 'correctly monetizes amount_paid_cents' do
expect(purchase.purchase_price).to be_a(Money)
expect(purchase.purchase_price.currency.iso_code).to eq('USD')
expect(purchase.purchase_price.fractional).to eq(1000)
end
end

describe 'self#purchase' do
let!(:participant) { create(:user) }
let!(:ticket_1) { create(:ticket) }
Expand Down
Loading

0 comments on commit acb36a5

Please sign in to comment.