require "test_helper" class PayoutTest < ActiveSupport::TestCase setup do @user = User.create!(email: "test@example.com", password: "password123", is_professionnal: true) @event = Event.create!( user: @user, name: "Test Event", slug: "test-event", description: "Test event description", venue_name: "Test Venue", venue_address: "Test Address", latitude: 48.8566, longitude: 2.3522, start_time: 1.day.ago, end_time: 1.hour.ago, state: :published ) # Create some earnings for the event Earning.create!(event: @event, user: @user, order: Order.create!(user: @user, event: @event, status: :paid, total_amount_cents: 1000), amount_cents: 2000, fee_cents: 200, status: :pending) @payout = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100) end test "should be valid" do assert @payout.valid? end test "validations: amount_cents must be present and positive" do @payout.amount_cents = nil assert_not @payout.valid? assert_includes @payout.errors[:amount_cents], "can't be blank" @payout.amount_cents = 0 assert_not @payout.valid? assert_includes @payout.errors[:amount_cents], "must be greater than 0" @payout.amount_cents = -100 assert_not @payout.valid? assert_includes @payout.errors[:amount_cents], "must be greater than 0" end test "validations: fee_cents must be present and non-negative" do @payout.fee_cents = nil assert_not @payout.valid? assert_includes @payout.errors[:fee_cents], "can't be blank" @payout.fee_cents = -100 assert_not @payout.valid? assert_includes @payout.errors[:fee_cents], "must be greater than or equal to 0" end test "validations: net earnings must be greater than 0" do # Create an event with no earnings (net earnings = 0) event_without_earnings = Event.create!( user: @user, name: "Test Event", slug: "test-event-2", description: "Test event description", venue_name: "Test Venue", venue_address: "Test Address", latitude: 48.8566, longitude: 2.3522, start_time: 1.day.ago, end_time: 1.hour.ago, state: :published ) payout = Payout.new(user: @user, event: event_without_earnings, amount_cents: 1000, fee_cents: 100) assert_not payout.valid? assert_includes payout.errors[:base], "net earnings must be greater than 0" # Custom validation message end test "validations: only one pending payout per event" do pending_payout = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100, status: :pending) assert pending_payout.valid? duplicate = Payout.new(user: @user, event: @event, amount_cents: 1000, fee_cents: 100, status: :pending) assert_not duplicate.valid? assert_includes duplicate.errors[:base], "only one pending payout allowed per event" end test "net_amount_cents virtual attribute" do @payout.amount_cents = 10000 @payout.fee_cents = 1000 assert_equal 9000, @payout.net_amount_cents end test "after_create callback sets refunded_orders_count" do # Create some refunded tickets to test the callback order = Order.create!(user: @user, event: @event, status: :paid, total_amount_cents: 1000) ticket_type = TicketType.create!(event: @event, name: "General Admission", price_cents: 1000, quantity: 10) ticket = Ticket.create!(order: order, ticket_type: ticket_type, price_cents: 1000, status: :refunded) payout = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100) # The refunded_orders_count should be set by the callback assert_equal 1, payout.refunded_orders_count end test "associations: belongs to user" do association = Payout.reflect_on_association(:user) assert_equal :belongs_to, association.macro end test "associations: belongs to event" do association = Payout.reflect_on_association(:event) assert_equal :belongs_to, association.macro end test "status enum" do assert_equal 0, Payout.statuses[:pending] assert_equal 1, Payout.statuses[:processing] assert_equal 2, Payout.statuses[:completed] assert_equal 3, Payout.statuses[:failed] @payout.status = :pending assert @payout.pending? @payout.status = :completed assert @payout.completed? end test "pending scope" do pending = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100, status: :pending) completed = Payout.create!(user: @user, event: @event, amount_cents: 2000, fee_cents: 200, status: :completed) assert_includes Payout.pending, pending assert_not_includes Payout.pending, completed end test "manual_payout? returns true for manual payouts" do payout = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100, stripe_payout_id: "MANUAL_abc123") assert payout.manual_payout? end test "manual_payout? returns false for Stripe payouts" do payout = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100, stripe_payout_id: "tr_123") assert_not payout.manual_payout? end test "manual_payout? returns false when no stripe_payout_id" do payout = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100) assert_not payout.manual_payout? end test "mark_as_manually_processed! updates status and creates manual ID" do payout = Payout.create!(user: @user, event: @event, amount_cents: 1000, fee_cents: 100, status: :pending) payout.mark_as_manually_processed! assert payout.completed? assert payout.manual_payout? assert_match /MANUAL_/, payout.stripe_payout_id end end