feat(promotion-code): Complete promotion code integration and testing
- Add comprehensive promotion code methods to Order model - Implement Stripe invoice integration for promotion code discounts - Display promotion codes on invoice with proper discount breakdown - Fix and enhance all unit tests for promotion code functionality - Add discount calculation with capping to prevent negative totals - Ensure promotion codes work across entire order lifecycle 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -582,6 +582,243 @@ class OrderTest < ActiveSupport::TestCase
|
||||
assert_equal 95.0, order.promoter_payout_euros
|
||||
end
|
||||
|
||||
# === Promotion Code Tests ===
|
||||
|
||||
test "subtotal_amount_cents should calculate total without discounts" do
|
||||
order = Order.create!(
|
||||
user: @user, event: @event, total_amount_cents: 0,
|
||||
status: "draft", payment_attempts: 0
|
||||
)
|
||||
|
||||
# Create ticket type and tickets
|
||||
ticket_type = TicketType.create!(
|
||||
name: "Test Ticket Type",
|
||||
description: "A valid description for the ticket type that is long enough",
|
||||
price_cents: 1500,
|
||||
quantity: 10,
|
||||
sale_start_at: Time.current,
|
||||
sale_end_at: Time.current + 1.day,
|
||||
requires_id: false,
|
||||
event: @event
|
||||
)
|
||||
|
||||
Ticket.create!(
|
||||
order: order,
|
||||
ticket_type: ticket_type,
|
||||
status: "draft",
|
||||
first_name: "John",
|
||||
last_name: "Doe"
|
||||
)
|
||||
|
||||
Ticket.create!(
|
||||
order: order,
|
||||
ticket_type: ticket_type,
|
||||
status: "draft",
|
||||
first_name: "Jane",
|
||||
last_name: "Doe"
|
||||
)
|
||||
|
||||
# Create promotion code
|
||||
promotion_code = PromotionCode.create!(
|
||||
code: "TESTCODE",
|
||||
discount_amount_cents: 500,
|
||||
user: @user,
|
||||
event: @event
|
||||
)
|
||||
|
||||
order.promotion_codes << promotion_code
|
||||
order.calculate_total!
|
||||
|
||||
assert_equal 3000, order.subtotal_amount_cents # 2 tickets * 1500 cents
|
||||
assert_equal 2500, order.total_amount_cents # 3000 - 500 discount
|
||||
end
|
||||
|
||||
test "subtotal_amount_euros should convert subtotal cents to euros" do
|
||||
order = Order.new(total_amount_cents: 2500)
|
||||
def order.subtotal_amount_cents; 3000; end
|
||||
assert_equal 30.0, order.subtotal_amount_euros
|
||||
end
|
||||
|
||||
test "discount_amount_cents should calculate total discount from promotion codes" do
|
||||
order = Order.create!(
|
||||
user: @user, event: @event, total_amount_cents: 0,
|
||||
status: "draft", payment_attempts: 0
|
||||
)
|
||||
|
||||
# Create ticket type and tickets for subtotal
|
||||
ticket_type = TicketType.create!(
|
||||
name: "Test Ticket Type",
|
||||
description: "A valid description for the ticket type that is long enough",
|
||||
price_cents: 2000,
|
||||
quantity: 10,
|
||||
sale_start_at: Time.current,
|
||||
sale_end_at: Time.current + 1.day,
|
||||
requires_id: false,
|
||||
event: @event
|
||||
)
|
||||
|
||||
Ticket.create!(
|
||||
order: order,
|
||||
ticket_type: ticket_type,
|
||||
status: "draft",
|
||||
first_name: "John",
|
||||
last_name: "Doe"
|
||||
)
|
||||
|
||||
# Create multiple promotion codes
|
||||
promo1 = PromotionCode.create!(
|
||||
code: "PROMO1",
|
||||
discount_amount_cents: 300,
|
||||
user: @user,
|
||||
event: @event
|
||||
)
|
||||
|
||||
promo2 = PromotionCode.create!(
|
||||
code: "PROMO2",
|
||||
discount_amount_cents: 700,
|
||||
user: @user,
|
||||
event: @event
|
||||
)
|
||||
|
||||
order.promotion_codes << [ promo1, promo2 ]
|
||||
order.calculate_total!
|
||||
|
||||
assert_equal 1000, order.discount_amount_cents # 300 + 700 (within 2000 subtotal)
|
||||
end
|
||||
|
||||
test "discount_amount_euros should convert discount cents to euros" do
|
||||
order = Order.new(total_amount_cents: 2000)
|
||||
def order.discount_amount_cents; 1000; end
|
||||
assert_equal 10.0, order.discount_amount_euros
|
||||
end
|
||||
|
||||
test "calculate_total! should apply promotion code discounts" do
|
||||
order = Order.create!(
|
||||
user: @user, event: @event, total_amount_cents: 0,
|
||||
status: "draft", payment_attempts: 0
|
||||
)
|
||||
|
||||
# Create ticket type and tickets
|
||||
ticket_type = TicketType.create!(
|
||||
name: "Test Ticket Type",
|
||||
description: "A valid description for the ticket type that is long enough",
|
||||
price_cents: 2000,
|
||||
quantity: 10,
|
||||
sale_start_at: Time.current,
|
||||
sale_end_at: Time.current + 1.day,
|
||||
requires_id: false,
|
||||
event: @event
|
||||
)
|
||||
|
||||
Ticket.create!(
|
||||
order: order,
|
||||
ticket_type: ticket_type,
|
||||
status: "draft",
|
||||
first_name: "John",
|
||||
last_name: "Doe"
|
||||
)
|
||||
|
||||
# Create promotion code
|
||||
promotion_code = PromotionCode.create!(
|
||||
code: "TESTCODE",
|
||||
discount_amount_cents: 500,
|
||||
user: @user,
|
||||
event: @event
|
||||
)
|
||||
|
||||
order.promotion_codes << promotion_code
|
||||
order.calculate_total!
|
||||
|
||||
assert_equal 2000, order.subtotal_amount_cents
|
||||
assert_equal 500, order.discount_amount_cents
|
||||
assert_equal 1500, order.total_amount_cents
|
||||
end
|
||||
|
||||
test "calculate_total! should handle zero total after promotion codes" do
|
||||
order = Order.create!(
|
||||
user: @user, event: @event, total_amount_cents: 0,
|
||||
status: "draft", payment_attempts: 0
|
||||
)
|
||||
|
||||
# Create ticket type and tickets
|
||||
ticket_type = TicketType.create!(
|
||||
name: "Test Ticket Type",
|
||||
description: "A valid description for the ticket type that is long enough",
|
||||
price_cents: 500,
|
||||
quantity: 10,
|
||||
sale_start_at: Time.current,
|
||||
sale_end_at: Time.current + 1.day,
|
||||
requires_id: false,
|
||||
event: @event
|
||||
)
|
||||
|
||||
Ticket.create!(
|
||||
order: order,
|
||||
ticket_type: ticket_type,
|
||||
status: "draft",
|
||||
first_name: "John",
|
||||
last_name: "Doe"
|
||||
)
|
||||
|
||||
# Create promotion code that covers the entire amount
|
||||
promotion_code = PromotionCode.create!(
|
||||
code: "FULLDISCOUNT",
|
||||
discount_amount_cents: 500,
|
||||
user: @user,
|
||||
event: @event
|
||||
)
|
||||
|
||||
order.promotion_codes << promotion_code
|
||||
order.calculate_total!
|
||||
|
||||
assert_equal 500, order.subtotal_amount_cents
|
||||
assert_equal 500, order.discount_amount_cents
|
||||
assert_equal 0, order.total_amount_cents
|
||||
assert order.free?
|
||||
end
|
||||
|
||||
test "calculate_total! should not allow negative totals with promotion codes" do
|
||||
order = Order.create!(
|
||||
user: @user, event: @event, total_amount_cents: 0,
|
||||
status: "draft", payment_attempts: 0
|
||||
)
|
||||
|
||||
# Create ticket type and tickets
|
||||
ticket_type = TicketType.create!(
|
||||
name: "Test Ticket Type",
|
||||
description: "A valid description for the ticket type that is long enough",
|
||||
price_cents: 300,
|
||||
quantity: 10,
|
||||
sale_start_at: Time.current,
|
||||
sale_end_at: Time.current + 1.day,
|
||||
requires_id: false,
|
||||
event: @event
|
||||
)
|
||||
|
||||
Ticket.create!(
|
||||
order: order,
|
||||
ticket_type: ticket_type,
|
||||
status: "draft",
|
||||
first_name: "John",
|
||||
last_name: "Doe"
|
||||
)
|
||||
|
||||
# Create promotion code that exceeds the ticket amount
|
||||
promotion_code = PromotionCode.create!(
|
||||
code: "TOOMUCH",
|
||||
discount_amount_cents: 1000,
|
||||
user: @user,
|
||||
event: @event
|
||||
)
|
||||
|
||||
order.promotion_codes << promotion_code
|
||||
order.calculate_total!
|
||||
|
||||
assert_equal 300, order.subtotal_amount_cents
|
||||
assert_equal 300, order.discount_amount_cents # Capped at subtotal
|
||||
assert_equal 0, order.total_amount_cents
|
||||
end
|
||||
|
||||
# === Stripe Integration Tests (Mock) ===
|
||||
|
||||
test "create_stripe_invoice! should return nil for non-paid orders" do
|
||||
|
||||
Reference in New Issue
Block a user