require "test_helper" require "stripe" class PayoutServiceTest < ActiveSupport::TestCase setup do @user = users(:one) @event = events(:concert_event) @payout = Payout.create!(user: @user, event: @event, amount_cents: 9000, fee_cents: 1000) Stripe.api_key = "test_key" end test "process! success creates transfer and updates status" do # Mock Stripe Transfer Stripe::Transfer.expects(:create).with( amount: 90, # cents to euros currency: "eur", destination: @user.stripe_connected_account_id, description: "Payout for event #{@event.name}" ).returns(stub(id: "tr_123", status: "succeeded")) @payout.update(status: :pending) service = PayoutService.new(@payout) service.process! @payout.reload assert_equal :completed, @payout.status assert_equal "tr_123", @payout.stripe_payout_id assert @payout.earnings.update_all(status: :paid) # assume update_earnings_status end test "process! failure with Stripe error sets status to failed" do Stripe::Transfer.expects(:create).raises(Stripe::CardError.new("Insufficient funds")) @payout.update(status: :pending) service = PayoutService.new(@payout) assert_raises Stripe::CardError do service.process! end @payout.reload assert_equal :failed, @payout.status assert_not_nil @payout.error_message # assume logged end test "process! idempotent for already completed" do @payout.update(status: :completed, stripe_payout_id: "tr_456") Stripe::Transfer.expects(:create).never service = PayoutService.new(@payout) service.process! @payout.reload assert_equal :completed, @payout.status end test "update_earnings_status marks earnings as paid" do earning1 = Earning.create!(event: @event, user: @user, order: orders(:one), amount_cents: 4500, fee_cents: 500, status: :pending) earning2 = Earning.create!(event: @event, user: @user, order: orders(:two), amount_cents: 4500, fee_cents: 500, status: :pending) @payout.earnings << earning1 @payout.earnings << earning2 service = PayoutService.new(@payout) service.update_earnings_status(:paid) assert_equal :paid, earning1.reload.status assert_equal :paid, earning2.reload.status end test "process! handles manual processing when user has no stripe account" do # Create a user without a stripe account user_without_stripe = User.create!( email: "test@example.com", password: "password123", is_professionnal: true ) event = Event.create!( user: user_without_stripe, 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 ) payout = Payout.create!(user: user_without_stripe, event: event, amount_cents: 9000, fee_cents: 1000, status: :pending) # Mock that Stripe is not available for this user user_without_stripe.stubs(:has_stripe_account?).returns(false) service = PayoutService.new(payout) service.process! payout.reload assert_equal :completed, payout.status assert payout.manual_payout? assert_match /MANUAL_/, payout.stripe_payout_id end end