armandofox/audience1st

View on GitHub
app/controllers/reports_controller.rb

Summary

Maintainability
B
5 hrs
Test Coverage
D
64%
class ReportsController < ApplicationController

  before_filter :is_staff_filter

  def index
    season = Time.at_beginning_of_season
    @recent_showdates = Showdate.where(:thedate => (season - 1.years .. season + 1.year)).order(:thedate)
    # next showdate
    @next_showdate = Showdate.current_or_next
    # all show names
    @all_shows = Show.all.order('listing_date DESC')
    # currently playing show
    @current_show = @next_showdate.try(:show) || @all_shows.first
    # quick subscription stats
    @subscriptions = SubscriptionSalesReport.new(Time.this_season).run.vouchers_for_display
    # list of all special reports
    @special_report_names = Report.subclasses.map { |s| ActiveModel::Name.new(s).human }.sort.unshift('Select report...')
  end

  def advance_sales
    show_ids = params[:shows]
    redirect_to(reports_path, :alert => "Please select one or more shows.") if show_ids.blank?
    @shows = Show.where(:id => show_ids).includes(:showdates => :vouchers)
    return unless params[:commit] =~ /download/i # fall through to render on screen
    report = ShowAdvanceSalesReport.new(@shows).generate
    if report.errors.empty?
      download_to_excel(report.csv, "sales_by_show")
    else
      redirect_to(reports_path, :alert => report.errors.as_html)
    end
  end

  def showdate_sales
    entity = Object.const_get(params[:klass])
    render :status => :unprocessable_entity and return unless (entity == Show || entity == Showdate)
    entity = entity.find(params[:id])
    vouchers = entity.vouchers.finalized

    sales = Showdate::Sales.new(vouchers.group_by(&:vouchertype),
      entity.revenue_per_seat, entity.total_offered_for_sale)
    render :partial => 'showdate_sales', :locals => { :sales => sales }
  end

  def subscriber_details
    season = (params[:id] || Time.current.year).to_i
    report = SubscriptionSalesReport.new(season).run
    if params[:download]
      report.generate_csv
      download_to_excel(report.csv, "subs-#{season}")
    else
      render :partial => 'subscriptions', :object => report.vouchers_for_display, :locals => {:year => season}
    end
  end

  def  attendance
    report_name = params[:special_report_name].to_s.gsub(/\s+/, '_').downcase
    return unless report_subclass = validate_report_type(report_name)
    @report = report_subclass.__send__(:new)
    @args = @report.view_params
    @sublists = EmailList.new.get_sublists
    render :partial => "reports/special_report", :locals => {:name => report_name}
  end

  # This handler is always called as XHR GET, but for one case ("display
  # matches on screen"), it must do a full HTTP redirect.
  skip_before_filter :verify_authenticity_token, :only => :run_special, :if => lambda { request.xhr? }
  def run_special
    return unless (klass = validate_report_type params[:report_name])
    action = params[:what]
    full_report_url = request.fullpath
    @report = klass.__send__(:new, params[:output])
    @report.generate_and_postprocess(params)
    @customers = @report.customers

    if @report.errors
      return render(:js => %Q{alert('#{ActionController::Base.helpers.j @report.errors}')})
    end
    
    if request.xhr? && action =~ /display|download/i
      # if we need a true redirect (for Download or Display On Screen),
      # serialize the form and use JS to force the redirect.  This means we end up
      # running the report twice, but whatever.
      if action =~ /new/        # open in new window/tab
        return render(:js => %Q{window.open("#{full_report_url}");})
      else
        return render(:js => %Q{window.location.href = '#{full_report_url}';})
      end
    end

    case action
    when /display/i
      # paginate in case it's a long report
      @customers = @customers.paginate(:page => (params[:page] || 1).to_i)
      @page_title = "Report results: #{params[:report_name].humanize}"
      @list_action = full_report_url
      render :template => 'customers/index'
    when /estimate/i
      render :js => "alert('#{@customers.length} matches')"
    when /download/i
      @report.create_csv
      stream_download_to_excel(@report.output, @report.filename)
    when /add/i
      seg = params[:sublist]
      email_list = EmailList.new
      result = email_list.add_to_sublist(seg, @customers)
      msg = "#{result} customers added to list '#{seg}'. #{email_list.errors}"
      render :js => %Q{alert(#{msg})}
    when /create/i
      name = params[:sublist_name]
      email_list = EmailList.new
      if (num=email_list.create_sublist_with_customers(name, @customers))
        msg = ActionController::Base.helpers.escape_javascript %Q{List "#{name}" created with #{num} customers. #{email_list.errors}}
      else
        msg = ActionController::Base.helpers.escape_javascript %Q{Error creating list "#{name}": #{email_list.errors}}
      end
      render :js => %Q{alert('#{msg}')}
    else
      raise "Unmatched action #{action}"
    end
  end

  def unfulfilled_orders
    @report = UnfulfilledOrdersReport.new
    return redirect_to(reports_path, :notice => 'No unfulfilled orders at this time.') if @report.empty
    if params[:csv]
      send_data @report.as_csv, :type => 'text/csv', :filename => "unfulfilled_#{Date.today}.csv"
    end
  end

  def mark_fulfilled
    i = 0
    flash[:notice] = ''
    params[:voucher].each_pair do |vid,do_update|
      next if do_update.to_i.zero?
      if (v = Voucher.find_by_id(vid))
        unless v.fulfillment_needed
          flash[:notice] << "Warning: voucher ID #{vid} was already marked fulfilled<br/>"
        end
        v.fulfillment_needed = false
        v.save!
        i += 1
      end
    end
    redirect_to({:action => 'index'}, {:notice =>  "#{i} orders marked fulfilled"})
  end

  def revenue_by_payment_method
    # report may be by date range or by production
    case params[:txn_report_by]
    when 'date'
      from,to = Time.range_from_params(params[:txn_report_dates])
      return redirect_to(reports_path, :alert => 'Please select a date range of 3 months or less for the Revenue Details report.') if (to - from > 93.days)
      @report = RevenueByPaymentMethodReport.new.by_dates(from,to)
    when 'showdate'
      @report = RevenueByPaymentMethodReport.new.by_showdate_id(params[:txn_report_showdate_id])
    when 'production'
      @report = RevenueByPaymentMethodReport.new.by_show_id(params[:txn_report_show_id])
    else
      return redirect_to(reports_path, :alert => "Invalid report type: #{params[:txn_report_by]}")
    end
    return redirect_to(reports_path, :alert => @report.errors.as_html) unless @report.run
    if params[:commit] =~ /download/i # fall thru to screen display
      return ((csv = @report.csv) ?
        download_to_excel(@report.csv, 'revenue_details') :
        redirect_to(reports_path, :alert => @report.errors.as_html))
    end
  end

  def retail
    @from,@to = Time.range_from_params(params[:retail_report_dates])
    @items = RetailItem.
      joins(:order).
      where(:sold_on => @from..@to).
      order(:sold_on)
    return redirect_to(reports_path, :notice => 'No retail purchases match these criteria.') if @items.empty?
  end
  

  private

  def validate_report_type(str)
    klass = str.camelize.constantize
    valid = klass.ancestors.include?(Report)
    redirect_to(reports_path, :alert => "Invalid report name '#{str}'") unless valid
    valid && klass
  end

end