feat(payouts): implement promoter earnings viewing, request flow, and admin Stripe processing with webhooks
Add model methods for accurate net calculations (€0.50 + 1.5% fees), eligibility, refund handling Update promoter/payouts controller for index (pending events), create (eligibility checks) Integrate admin processing via Stripe::Transfer, webhook for status sync Enhance views: index pending cards, events/show preview/form Add comprehensive tests (models, controllers, service, integration); run migrations
This commit is contained in:
@@ -1,54 +1,61 @@
|
||||
class Promoter::PayoutsController < ApplicationController
|
||||
before_action :authenticate_user!
|
||||
before_action :ensure_promoter!
|
||||
before_action :set_event, only: [:show, :create]
|
||||
before_action :set_event, only: [ :create ]
|
||||
|
||||
# List all payouts for the current promoter
|
||||
def index
|
||||
@payouts = current_user.payouts
|
||||
.includes(:event)
|
||||
.order(created_at: :desc)
|
||||
.page(params[:page])
|
||||
@payouts = current_user.payouts.completed.order(created_at: :desc).page(params[:page])
|
||||
|
||||
@eligible_events = current_user.events.eligible_for_payout.includes(:earnings).limit(5)
|
||||
@total_pending_net = @eligible_events.sum(&:net_earnings_cents)
|
||||
|
||||
@total_paid_out = current_user.payouts.completed.sum(&:net_amount_cents)
|
||||
@total_pending = @total_pending_net
|
||||
@total_payouts_count = current_user.payouts.count
|
||||
end
|
||||
|
||||
# Show payout details
|
||||
def show
|
||||
@payout = @event.payouts.find(params[:id])
|
||||
@payout = current_user.payouts.find(params[:id])
|
||||
@event = @payout.event
|
||||
end
|
||||
|
||||
# Create a new payout request
|
||||
def create
|
||||
# Check if event can request payout
|
||||
unless @event.can_request_payout?
|
||||
redirect_to promoter_event_path(@event), alert: "Payout cannot be requested for this event."
|
||||
unless @event.can_request_payout?(current_user)
|
||||
redirect_to event_path(@event.slug, @event), alert: "Payout cannot be requested for this event."
|
||||
return
|
||||
end
|
||||
|
||||
# Calculate payout amount
|
||||
total_earnings_cents = @event.total_earnings_cents
|
||||
total_fees_cents = @event.total_fees_cents
|
||||
net_earnings_cents = @event.net_earnings_cents
|
||||
# Calculate payout amount using model methods
|
||||
gross = @event.total_gross_cents
|
||||
fees = @event.total_fees_cents
|
||||
|
||||
# Count orders
|
||||
total_orders_count = @event.orders.where(status: ['paid', 'completed']).count
|
||||
refunded_orders_count = @event.tickets.where(status: 'refunded').joins(:order).where(orders: {status: ['paid', 'completed']}).count
|
||||
# Count orders using model scope
|
||||
total_orders_count = @event.orders.paid.count
|
||||
|
||||
# Create payout record
|
||||
@payout = @event.payouts.build(
|
||||
user: current_user,
|
||||
amount_cents: total_earnings_cents,
|
||||
fee_cents: total_fees_cents,
|
||||
total_orders_count: total_orders_count,
|
||||
refunded_orders_count: refunded_orders_count
|
||||
amount_cents: gross,
|
||||
fee_cents: fees,
|
||||
total_orders_count: total_orders_count
|
||||
)
|
||||
# refunded_orders_count will be set by model callback
|
||||
|
||||
if @payout.save
|
||||
# Update event payout status
|
||||
@event.update!(payout_status: :requested, payout_requested_at: Time.current)
|
||||
|
||||
|
||||
# Log notification (mailer can be added later if needed)
|
||||
Rails.logger.info "Payout request submitted: #{@payout.id} for event #{@event.id}"
|
||||
|
||||
redirect_to promoter_payout_path(@payout), notice: "Payout request submitted successfully."
|
||||
else
|
||||
redirect_to promoter_event_path(@event), alert: "Failed to submit payout request: #{@payout.errors.full_messages.join(', ')}"
|
||||
flash.now[:alert] = "Failed to submit payout request: #{@payout.errors.full_messages.join(', ')}"
|
||||
render "new"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -63,4 +70,4 @@ class Promoter::PayoutsController < ApplicationController
|
||||
def set_event
|
||||
@event = current_user.events.find(params[:event_id])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user