MiraitSystems/enju_trunk

View on GitHub
app/controllers/export_item_lists_controller.rb

Summary

Maintainability
D
2 days
Test Coverage
class ExportItemListsController < ApplicationController
  before_filter :check_librarian

  def initialize
    @list_types = [[t('item_list.shelf_list'),1],
                   [t('item_list.call_number_list'), 2],
                   [t('item_list.removed_list'), 3],
                   [t('item_list.unused_list'), 4],
                   [t('item_list.series_statements_list'), 8],
                   [t('item_list.new_item_list'), 5],
                   [t('item_list.latest_list'), 6],
                   [t('item_list.new_book_list'), 7]
                 ]
    @libraries = Library.all
    @carrier_types = CarrierType.all
    @bookstores = Bookstore.all
    @selected_list_type = 1
    @selected_library, @selected_carrier_type, @selected_bookstore = [], [], []
    super
  end

  def index
    @selected_library = @libraries.map(&:id)
    @selected_carrier_type = @carrier_types.map(&:id)
    @selected_bookstore = @bookstores.map(&:id)
    @items_size = Item.count(:all, :joins => [:manifestation, :shelf => :library])
    @page = (@items_size / 36).to_f.ceil
  end

  def create
    # check checked
    @selected_list_type = params[:export_item_list][:list_type]
    @selected_library = params[:library].map(&:to_i) if params[:library]
    @selected_carrier_type = params[:carrier_type].map(&:to_i) if params[:carrier_type]
    @selected_bookstore = params[:bookstore].map(&:to_i) if params[:bookstore]
    booksotre_ids = params[:all_bookstore] == 'true' ? :all : @selected_bookstore

    @ndc = params[:ndc]
    @acquired_at = params[:acquired_at].to_s.dup

    list_type = params[:export_item_list][:list_type].to_i
    file_type = params[:export_item_list][:file_type]

    unless %w(pdf tsv).include?(file_type)
      raise BadParameter, [t('item_list.invalid_file_type')]
    end

    ndcs, acquired_at = parse_list_params(
      @selected_library,
      @selected_carrier_type,
      booksotre_ids,
      @ndc,
      @acquired_at)
    scope, filename = construct_list_query(
      list_type,
      @selected_library,
      @selected_carrier_type,
      booksotre_ids,
      ndcs,
      acquired_at,
      true)

    # make file
    args = []
    case list_type
    when 3
      method = 'make_export_removed_list'
    when 5
      method = 'make_export_new_item_list'
    when 6
      method = 'make_export_series_statements_latest_list'
    when 7
      method = 'make_export_new_book_list'
    when 8
      method = 'make_export_series_statements_list'
      args << acquired_at
    else
      method = 'make_export_item_list'
      args << filename if file_type == 'pdf'
    end

    dumped_scope = Marshal.dump(scope)
    job_name = Item.make_export_item_list_job(filename, file_type, method, dumped_scope, args, current_user)
    flash[:message] = t('item_list.export_job_queued', :job_name => job_name)
    redirect_to export_item_lists_path
    return true

  rescue BadParameter => e
    flash[:message] = e.errors.join('<br />')
    @items_size = 0
    @page = 0
    render :index
    return false

  rescue Exception => e
    logger.error "failed #{e}"
    logger.debug "Exception: #{e.message} (#{e.class})"
    logger.debug "\t" + e.backtrace.join("\n\t")
    render :nothing => true, :status => :internal_server_error
    return false
  end

  def get_list_size
    unless request.xhr? && params[:list_type].present?
      render :nothing => true, :status => :not_found
      return
    end

    list_type = params[:list_type]
    ndcs = params[:ndc]
    libraries = params[:libraries]
    carrier_types = params[:carrier_types]
    bookstores = params[:bookstores]
    acquired_at = params[:acquired_at]
    libraries = libraries.map{|library|library.to_i} if libraries
    carrier_types = carrier_types.map{|carrier_type|carrier_type.to_i} if carrier_types
    bookstores = bookstores.map{|bookstore|bookstore.to_i} if bookstores
    booksotres = params[:all_bookstore] == 'true' ? :all : bookstore

    ndcs, acquired_at = parse_list_params(
      libraries,
      carrier_types,
      booksotres,
      ndcs,
      acquired_at,
      false)
    scope, = construct_list_query(
      list_type.to_i,
      libraries,
      carrier_types,
      booksotres,
      ndcs,
      acquired_at,
      false)

    # list_size
    list_size = scope.count rescue 0

    #page
    page = (list_size / 36).to_f.ceil
    page = 1 if page == 0

    render :json => {:success => 1, :list_size => list_size, :page => page}

  rescue BadParameter => e
    logger.debug e.errors.join(', ')
    render :json => {:success => 1, :list_size => 0, :page => 0}

  rescue Exception => e
    logger.error e
    render :json => {:success => 0, :list_size => 0, :page => 0}
  end

  private

  # パラメータ(文字列)で与えられた条件を解析する。
  # NDCリストと受入日はしかるべき値に変換する。
  def parse_list_params(library_ids, carrier_type_ids, bookstore_ids, ndcs, acquired_at, deny_blank_bookstore_ids = true)
    error = []

    # check required params
    error << t('item_list.no_list_condition') if library_ids.blank? || carrier_type_ids.blank? || (deny_blank_bookstore_ids && bookstore_ids.blank?)

    # check and convert ndc
    unless ndcs.blank? 
      ndcs = ndcs.gsub(' ', '').split(",") 
      ndcs.each do |ndc|
        unless ndc =~ /^\d{3}$/
          logger.error ndc
          error << t('item_list.invalid_ndc')
          break
        end
      end
    end

    # check and convert acquired_at
    unless acquired_at.blank?
      acquired_at = acquired_at.to_s.gsub(/\D/, '')
      begin
        acquired_at = Time.zone.parse(acquired_at).beginning_of_day.utc.iso8601
      rescue
        error << t('item_list.acquired_at_invalid')
      end
    end

    # fail on errors
    raise BadParameter.new(error) unless error.blank?

    [ndcs, acquired_at]
  end

  # 指定されたパラメータに応じて
  # 出力するリストのためのクエリーと、
  # 指定に応じたファイル名を返す
  def construct_list_query(list_type, library_ids, carrier_type_ids, bookstore_ids, ndcs, acquired_at, apply_order)
    scope = Item.scoped

    ti = Item.arel_table
    tc = Checkout.arel_table

    case list_type
    when 1
      scope = scope.
        where_ndcs_libraries_carrier_types(ndcs, library_ids, carrier_type_ids).
        joins(:manifestation, :shelf => :library)
      order = 'libraries.id, manifestations.carrier_type_id, shelves.id, manifestations.ndc'
      filename = t('item_list.shelf_list')

    when 2
      scope = scope.
        joins(:manifestation, :shelf => :library).
        where(["libraries.id in (?) AND manifestations.carrier_type_id in (?)", library_ids, carrier_type_ids])
      order = 'items.call_number'
      filename = t('item_list.call_number_list')

    when 3
      scope = scope.
        joins(:manifestation, :circulation_status, :shelf => :library).
        where(["libraries.id in (?) AND manifestations.carrier_type_id in (?) AND circulation_statuses.name = ?",
              library_ids, carrier_type_ids, 'Removed'])
      order = 'libraries.id, manifestations.carrier_type_id, items.shelf_id, items.item_identifier, manifestations.original_title'
      filename = t('item_list.removed_list')

    when 4
      scope = scope.
        joins(:manifestation, :shelf => :library).
        where("libraries.id in (?) AND manifestations.carrier_type_id in (?)",
              library_ids, carrier_type_ids).
        where(ti[:id].not_in(tc.project(:item_id)))
      order = 'libraries.id, manifestations.carrier_type_id, items.shelf_id, items.item_identifier'
      filename = t('item_list.unused_list')

    when 5
      scope = scope.
        recent.
        where_ndcs_libraries_carrier_types(ndcs, library_ids, carrier_type_ids).
        joins(:manifestation, :shelf => :library)
      order = 'libraries.id, manifestations.carrier_type_id, items.shelf_id, items.item_identifier, manifestations.original_title'
      filename = t('item_list.new_item_list')

    when 6
      tm = Manifestation.arel_table
      tm2 = tm.alias("m2")
      tm3 = tm.alias("m3")
      tm4 = tm.alias("m4")
      ts = SeriesHasManifestation.arel_table
      ts2 = ts.alias("s2")

      max_sn_q =
        ts.project(
          ts[:series_statement_id],
          tm2[:id].minimum.as('id')
        ).
          join(tm2).on(
            ts[:manifestation_id].eq(tm2[:id])
          ).
          where(
            ts.from(ts2).
            project('*').
            join(tm3).on(
              ts2[:manifestation_id].eq(tm3[:id])
            ).
            where(
              ts2[:series_statement_id].eq(ts[:series_statement_id]).
              and(tm2[:serial_number].lt(tm3[:serial_number]))
            ).exists.not
          ).
          group(ts[:series_statement_id]).
          as('t')

      max_sn_manifestation_q =
        tm.project('*').
          from(tm4).
          join(ts).on(
            ts[:manifestation_id].eq(tm4[:id])
          ).
          join(max_sn_q).on(
            max_sn_q[:series_statement_id].eq(ts[:series_statement_id]).
            and(
              max_sn_q[:id].eq(tm4[:id])
            )
          ).
          as('m')

      scope = scope.
        joins(:shelf => :library)
      order = 'libraries.id, items.acquired_at, items.bookstore_id, items.item_identifier, items.id'

      filename = t('item_list.latest_list')

    when 7
      day_ago = Time.zone.now - SystemConfiguration.get("new_book_term").day
      scope = scope.
        where_ndcs_libraries_carrier_types(ndcs, library_ids, carrier_type_ids).
        joins(:manifestation, :shelf => :library).
        where(['manifestations.date_of_publication >= ?', day_ago])
      order = 'libraries.id, manifestations.carrier_type_id, items.shelf_id, items.item_identifier, manifestations.original_title'
      filename = t('item_list.new_book_list')

    when 8
      scope = scope.
        series_statements_item(library_ids, bookstore_ids, acquired_at)
      order = 'libraries.id, items.acquired_at, items.bookstore_id, items.item_identifier, items.id'
      filename = t('item_list.series_statements_list')
    end

    scope = scope.order(order) if apply_order
    [scope, filename]
  end

  class BadParameter < RuntimeError
    def initialize(errors)
      super()
      @errors = errors
    end
    attr_reader :errors
  end
end