feat: Implement promoter payout system for event revenue processing
- Add Payout model with associations to User and Event - Create payout requests for completed events with proper earnings calculation - Exclude refunded tickets from payout calculations - Add promoter dashboard views for managing payouts - Implement admin interface for processing payouts - Integrate with Stripe for actual payment processing - Add comprehensive tests for payout functionality Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -1,92 +1,30 @@
|
||||
class PayoutService
|
||||
def initialize(promoter_id = nil)
|
||||
@promoter_id = promoter_id
|
||||
def initialize(payout)
|
||||
@payout = payout
|
||||
end
|
||||
|
||||
def process_pending_payouts
|
||||
scope = Earnings.pending
|
||||
scope = scope.where(user_id: @promoter_id) if @promoter_id.present?
|
||||
def process!
|
||||
return unless @payout.can_process?
|
||||
|
||||
scope.includes(:user, :order, :event).group_by(&:user_id).each do |user_id, earnings|
|
||||
process_payout_for_user(user_id, earnings)
|
||||
end
|
||||
end
|
||||
|
||||
def process_event_payout(event)
|
||||
return unless event.can_request_payout?
|
||||
|
||||
earnings = event.earnings.pending
|
||||
total_cents = earnings.sum(:amount_cents)
|
||||
fees_cents = event.total_fees_cents
|
||||
net_cents = total_cents - fees_cents
|
||||
|
||||
return if net_cents <= 0
|
||||
@payout.update!(status: :processing)
|
||||
|
||||
# Create Stripe payout
|
||||
begin
|
||||
event.update!(payout_status: :processing)
|
||||
stripe_payout = Stripe::Payout.create({
|
||||
amount: @payout.amount_cents,
|
||||
currency: 'eur',
|
||||
destination: @payout.user.stripe_account_id,
|
||||
description: "Payout for event: #{@payout.event.name}"
|
||||
})
|
||||
|
||||
transfer = Stripe::Transfer.create(
|
||||
amount: net_cents / 100,
|
||||
currency: "eur",
|
||||
destination: event.user.stripe_account_id,
|
||||
description: "Payout for event: #{event.name}",
|
||||
metadata: {
|
||||
event_id: event.id,
|
||||
promoter_id: event.user_id,
|
||||
gross_amount: total_cents,
|
||||
fees: fees_cents,
|
||||
net_amount: net_cents
|
||||
}
|
||||
@payout.update!(
|
||||
status: :completed,
|
||||
stripe_payout_id: stripe_payout.id
|
||||
)
|
||||
|
||||
earnings.update_all(
|
||||
status: :paid,
|
||||
fee_cents: fees_cents,
|
||||
net_amount_cents: net_cents,
|
||||
stripe_payout_id: transfer.id
|
||||
)
|
||||
|
||||
event.update!(
|
||||
payout_status: :completed,
|
||||
payout_requested_at: Time.current
|
||||
)
|
||||
|
||||
Rails.logger.info "Processed event payout #{transfer.id} for event #{event.id}: €#{net_cents / 100.0}"
|
||||
rescue Stripe::StripeError => e
|
||||
event.update!(payout_status: :failed)
|
||||
Rails.logger.error "Payout failed for event #{event.id}: #{e.message}"
|
||||
@payout.update!(status: :failed)
|
||||
Rails.logger.error "Stripe payout failed for payout #{@payout.id}: #{e.message}"
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def process_payout_for_user(user_id, earnings)
|
||||
user = User.find(user_id)
|
||||
return unless user.stripe_account_id.present?
|
||||
|
||||
total_amount_cents = earnings.sum(:amount_cents)
|
||||
|
||||
begin
|
||||
transfer = Stripe::Transfer.create(
|
||||
amount: total_amount_cents / 100,
|
||||
currency: "eur",
|
||||
destination: user.stripe_account_id,
|
||||
description: "Payout for promoter #{user_id} - Total: €#{total_amount_cents / 100.0}",
|
||||
metadata: {
|
||||
promoter_id: user_id,
|
||||
earnings_ids: earnings.map(&:id).join(",")
|
||||
}
|
||||
)
|
||||
|
||||
earnings.update_all(
|
||||
status: :paid,
|
||||
stripe_payout_id: transfer.id
|
||||
)
|
||||
|
||||
Rails.logger.info "Processed payout #{transfer.id} for promoter #{user_id}: €#{total_amount_cents / 100.0}"
|
||||
rescue Stripe::StripeError => e
|
||||
Rails.logger.error "Failed to process payout for promoter #{user_id}: #{e.message}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user