class AcceptOrdersController < CommLogistics::Base::Controller::SuperiorOrder
  include Comm::Module::Controller::Logging
  include CommLogistics::Modules::Controller::ShowFilter
  include CommLogistics::Modules::Controller::ExtIndexFilter
  
  before_filter :create_consumer, :only => [:create, :update]
    
  def initialize
    @mcls = AcceptOrder
  end

  def auto_flow
    error_container=[]
    id_lists = params[:id_list].split(",")
    id_lists.each do |id|
      ac = AcceptOrder.find(id.to_i)
      begin
        if Rel.locked?(ac.class.to_s.tableize, id)
          raise "後続の伝票がすでに存在しているので自動処理できません。"
        end
        ActiveRecord::Base.transaction do
          flow_one_order(ac)
        end
      rescue => e
        # ほかの受注伝票を続行可能なエラー
        Rails.logger.error("Error one order \nID:"+[ac.id,e.message,e.backtrace].join("\n"))
        error_container << [ac.id, e.message]
      ensure
        ac.auto_flow_at = DateTime.now.to_s
        ac.save!
      end
    end
    unless error_container.empty?
      raise "自動フローエラー"
    end
    render :json => Comm::Tool::Json.result_json(true, '')
  rescue => e
    if params[:from_grid] == 'true'
      error_container.unshift(['受注ID','エラー内容',Time.now.strftime("%Y/%m/%d %H:%M").to_s+" 実行"])
      error_response = Comm::Module::CsvWriter.new.write(error_container, {:response=>false, :basename=>'AutoFlow_Error'})  
      render :json => error_response.to_json
    else
      if error_container.empty?
        emsg = e.message
      else
        emsg = error_container.shift.pop
      end
      #エラーを画面に返す場合は、改行文字を<br/>に置き換えて送信
      render :json => Comm::Tool::Json.result_json(false, emsg.gsub(/(\r\n|\r|\n)/, "<br />"))
    end
  end
  def flow_one_order(ac)
    trels = TableRel.target_rels(ac, 'accept_orders').supplier_filter(ac).find(:all)
    last = nil
    trels.each do |trel|
      Rails.logger.debug("accept_order id:"+ac.id.to_s+"\ntable_rels:"+trel.inspect)
      model = trel.make_model_instance
      if last and (trel.dependency_flag_code == 1 and last.complete? == false)
        #「依存」している場合は直前の処理が「完了」してなければ処理しない
        Rails.logger.info(trel.table_name+" is canceled by dependency.")
        last = model
        next
      end   
      model.parent = parent_info_to_hash(ac)
      model.session = session
      model.set_params(ac, params)
      #unless model.set_params(ac, params)
      #  Rails.logger.debug("set_params Fail\nModel\n"+model.table_params.inspect+"Detail\n"+model.detail_params.inspect)
      #  raise "必要なパラメータが作成できません。受注伝票や在庫を確認してください。"      
      #end
      Rails.logger.debug("set_params Success\nModel\n"+model.table_params.inspect+"\n"+model.detail_params.inspect)
      if trel.auto_flag_code == 1
        model.create_exec_auto_flow({:main=>model.table_params, :details=>model.detail_params})
      else
        model.create_not_auto_flow({:main=>model.table_params, :details=>model.detail_params})
      end
      last = model
    end
  end
  def parent_info_to_hash(ac)
    parent_hash = {}
    parent_hash[:table] = ac.class.table_name
    parent_hash[:rev] = ac.rev_number
    parent_hash[:id] = ac.id
    parent_hash
  end
  
  def create_consumer
    if params[:create_consumer]==STR_TRUE 
      @consumer_params = params[:consumer]
      @consumer_params[:invalid_flag_code]=MCODE_FLAG_OFF
      @consumer_params[:disp_name] = (@consumer_params[:last_name] ||"") + " " + (@consumer_params[:first_name] ||"") if !@consumer_params[:last_name].blank? && !@consumer_params[:first_name].blank?
      @consumer_params[:kana_name] = (@consumer_params[:last_kana_name] ||"") + " " + (@consumer_params[:first_kana_name] ||"") if !@consumer_params[:last_kana_name].blank? && !@consumer_params[:first_kana_name].blank?
      @consumer_params[:taker_disp_name] = (@consumer_params[:taker_last_name] ||"") + " " + (@consumer_params[:taker_first_name] ||"") if !@consumer_params[:taker_last_name].blank? && !@consumer_params[:taker_first_name].blank?
      @consumer_params[:taker_kana_name] = (@consumer_params[:taker_last_kana_name] ||"") + " " + (@consumer_params[:taker_first_kana_name] ||"") if !@consumer_params[:taker_last_kana_name].blank? && !@consumer_params[:taker_first_kana_name].blank?
      ar = Consumer.new
      result = ar.create_mng(@consumer_params, params[:master_rev])
      unless result
        render :json => {:success=>result, :message=>ar.errmsg}.to_json
      end
    end
  end
  
  #追加発注のためのオーバーライド。
  def create
    check_parent_revision
    @table_params[:invalid_flag_code] = MCODE_FLAG_OFF
    ar = @mcls.new
    ar.parent = @parent
    ar.session = session
    ar.additional = @additional
    result = ar.create_mng({:main => @table_params, :details => @details}, params[:master_rev])
    
    #新規作成で、追加発注があった場合は、受注のIDが発注伝票に設定されていないので後づけする。
    if result && !params[:add_order_ids].blank?
      add_order_ids = params[:add_order_ids].split(',')
      oars = Order.find(add_order_ids)
      oars.each do |oar|
        unless oar.update_attributes(:accept_order_id => ar.id)
          raise 'setting accept_order_id failed'
        end
      end
    end
    render :json => Comm::Tool::Json.result_json(result, ar.errmsg, get_respons(ar))
  rescue => e
    logger.error(e.message + "\n" + e.backtrace.join("\n"))
    render :json => Comm::Tool::Json.result_json(false, e.message, get_respons(ar))
  end
  
  def find_all_with_progress(flag)
    params[:session_user_id] = session[:user_id]
    ss = AcceptOrderSearch.new
    ss.table_alias = {'accept_orders' => 't'}
    return ss.search(flag, AcceptOrder, [], params)
  end
  
  #override===================
  #受注明細一覧に在庫や承認ステータスを表示する案はとりあえず、ボツ
  def get_sql_search
    require 'config/site_config.rb'
    ss = Comm::Tool::SqlSearch.new 
    if params[:action] == "with_details" && $SHOW_SHIPPING_FOR_ACCEPT_ORDER #アクションがwith_details
      ss = AcceptOrderDetailSearch.new
    else
      ss = Comm::Tool::SqlSearch.new
    end
    if params[:action] == "with_details" #アクションがwith_details
      column_name_array, non_table_columns = get_columns_for_with_details
      ss.parent_table_columns = column_name_array.join(',')
      ss.non_table_columns = non_table_columns
      if $SHOW_SHIPPING_FOR_ACCEPT_ORDER
        ss.non_table_columns.push("total_accept_order_quantity")
        ss.non_table_columns.push("total_shipping_quantity")
        ss.non_table_columns.push("total_unshipping_quantity")
      end
    end
    return ss
  end
  
  #受注明細一覧で、受注合計数、引き当て可能数、未検品数も含めて一覧表を作る。=>途中まで作ったけどとりあえず、ボツ
  class AcceptOrderDetailSearch < Comm::Tool::SqlSearch
    def get_columns_and_tables(tab, join_lists, params, str_vals)
      str_col, str_tab, str_vals = super
      
      str_tab = str_tab.sub("JOIN accept_order_details ON accept_orders.id = accept_order_details.accept_order_id",
                            "JOIN accept_order_details ON accept_orders.id = accept_order_details.accept_order_id
                             LEFT JOIN master_app_production.table_rels 
                               ON (accept_orders.sign_type_code=table_rels.sign_type_code OR accept_orders.sign_type_code IS NULL)
                              AND accept_orders.accept_order_type_code=table_rels.order_type_code 
                              AND table_rels.table_name='shippings'
                             LEFT JOIN (SELECT product_id, accept_orders.id AS accept_order_id, SUM(quantity) AS total_accept_order_quantity from accept_order_details 
                                   LEFT JOIN accept_orders ON accept_order_details.accept_order_id=accept_orders.id
                                   LEFT JOIN master_app_production.table_rels 
                                     ON (accept_orders.sign_type_code=table_rels.sign_type_code OR accept_orders.sign_type_code IS NULL)
                                    AND accept_orders.accept_order_type_code=table_rels.order_type_code 
                                    AND table_rels.table_name='shippings'
                                   WHERE accept_orders.state_code = #{MCODE_STATUS2_COMP}
                                     AND accept_orders.invalid_flag_code = #{MCODE_FLAG_OFF} 
                                     AND accept_orders.target_date BETWEEN '#{params[:start_target_date]}' AND '#{params[:end_target_date]}'
                                     AND table_rels.id IS NOT NULL
                                   GROUP BY product_id,accept_orders.id) AS tmp_aod ON accept_order_details.product_id=tmp_aod.product_id AND tmp_aod.accept_order_id=accept_orders.id
                             LEFT JOIN (SELECT product_id, accept_orders.id AS accept_order_id, SUM(IFNULL(quantity,0)) AS total_shipping_quantity FROM shipping_details 
                                   LEFT JOIN shippings ON shipping_details.shipping_id=shippings.id
                                   LEFT JOIN accept_orders ON accept_orders.id = shippings.accept_order_id
                                   WHERE accept_orders.state_code = #{MCODE_STATUS2_COMP}
                                     AND accept_orders.invalid_flag_code = #{MCODE_FLAG_OFF} 
                                     AND accept_orders.target_date BETWEEN '#{params[:start_target_date]}' AND '#{params[:end_target_date]}'
                                     AND shippings.shipping_state_code != #{MCODE_SHIPPING_STATE_BO}
                                   GROUP BY product_id, accept_orders.id) AS tmp_sd ON accept_order_details.product_id=tmp_sd.product_id AND tmp_sd.accept_order_id=accept_orders.id
                            ")
      str_col = str_col + ', IFNULL(tmp_aod.total_accept_order_quantity,0) AS total_accept_order_quantity, IFNULL(tmp_sd.total_shipping_quantity,0) AS total_shipping_quantity, IFNULL(tmp_aod.total_accept_order_quantity,0) - IFNULL(tmp_sd.total_shipping_quantity,0) AS total_unshipping_quantity '
      return str_col, str_tab, str_vals
    end
    def set_additional_where(str_where, params)
      if !params[:table_from].blank? && params[:table_from]=='accept_orders_stocks_lists'
        if str_where.blank?
          str_where = " WHERE "
        else
          str_where << " AND "
        end
        str_where << " accept_order_details.product_id=#{params[:product_id]} 
                   AND accept_orders.supplier_id=#{params[:supplier_id]}
                   AND accept_orders.invalid_flag_code=#{MCODE_FLAG_OFF}
                   AND accept_orders.state_code=#{MCODE_STATUS2_COMP}
                   AND table_rels.id IS NOT NULL"
      end
      return str_where
    end
  end

  class AcceptOrderSearch < Comm::Tool::SqlSearch
    def get_columns_and_tables(tab, join_lists, params, str_vals)
      #idの範囲を割り出しておく。高速化のため
#      ar = AcceptOrder.find_by_sql(["SELECT MIN(id) AS min_id, MAX(id) AS max_id FROM accept_orders
#                                     WHERE target_date between ? AND  ? ", params[:start_target_date], params[:end_target_date]])
#      if ar.length > 0
#        min_id = ar[0].min_id.to_i
#        max_id = ar[0].max_id.to_i
#      else
#        min_id = 0;
#        max_id = 0;
#      end
      
      invalid_vals = (!params || params[:with_invalid]==STR_TRUE) ? '0,1' : '0'
      
      str_cols = ' * '
#      str_tab =  " FROM (SELECT 
#                           a.*,
#                           IF(a.total_quantity=0,
#                            IF(b.cnt=0,0,IF(b.total_quantity=0,100,50)),
#                            100 * (IFNULL(b.total_quantity, 0)) /
#                             ((t.sales_cnt + IF(a.supplier_id=#{App::Const::SystemCode::OWN_SUPPLIER_ID},0,t.purchases_cnt) + IF(a.accept_order_trigger_code=#{MCODE_ACCEPT_ORDER_TRIGGER_SALES_AND_STOCKS},t.trans_cnt,0)) * a.total_quantity) 
#                           ) AS progress
#                         FROM accept_orders AS a 
#                         LEFT JOIN (
#                           SELECT accept_order_id, COUNT(*) AS cnt, SUM(total_quantity) AS total_quantity FROM (
#                             SELECT 'shippings' AS table_name, id, accept_order_id, total_quantity FROM shippings 
#                               WHERE shipping_state_code=#{MCODE_SHIPPING_STATE_COMP} AND invalid_flag_code=#{MCODE_FLAG_OFF} AND accept_order_id between #{min_id} and #{max_id} 
#                             UNION SELECT 'restorations' AS table_name, id, accept_order_id, total_quantity FROM restorations
#                               WHERE state_code=#{MCODE_STATUS2_COMP} AND invalid_flag_code=#{MCODE_FLAG_OFF} AND accept_order_id between #{min_id} and #{max_id}
#                             UNION SELECT 'purchases' AS table_name, id, accept_order_id, total_quantity FROM purchases
#                               WHERE state_code=#{MCODE_STATUS2_COMP} AND invalid_flag_code=#{MCODE_FLAG_OFF} AND accept_order_id between #{min_id} and #{max_id} AND purchase_trigger_code != #{MCODE_PURCHASE_TRIGGER_ACCEPT_ORDER}
#                             UNION SELECT 'sales' AS table_name, id, accept_order_id, total_quantity FROM sales
#                               WHERE state_code=#{MCODE_STATUS2_COMP} AND invalid_flag_code=#{MCODE_FLAG_OFF} AND accept_order_id between #{min_id} and #{max_id}
#                             UNION SELECT 'samples' AS table_name, id, accept_order_id, total_quantity FROM samples
#                               WHERE state_code=#{MCODE_STATUS2_COMP} AND invalid_flag_code=#{MCODE_FLAG_OFF} AND accept_order_id between #{min_id} and #{max_id}
#                           ) AS tmp GROUP BY accept_order_id
#                         ) AS b ON a.id=b.accept_order_id
#                         LEFT JOIN (SELECT 
#                                      order_type_code, 
#                                      SUM(IF(table_name='sales',1,0)) AS sales_cnt, 
#                                      SUM(IF(table_name='purchases',1,0)) AS purchases_cnt,
#                                      SUM(IF(table_name!='sales' AND table_name!='purchases' AND table_name!='orders',1,0)) AS trans_cnt
#                                    FROM master_app_production.table_rels 
#                                    WHERE invalid_flag_code=#{MCODE_FLAG_OFF} 
#                                    GROUP BY order_type_code
#                                  ) AS t ON a.accept_order_type_code=t.order_type_code  
#                         WHERE a.target_date BETWEEN \"#{params[:start_target_date]}\" AND \"#{params[:end_target_date]}\"
#                           AND a.invalid_flag_code IN (#{invalid_vals})
#                   ) AS t "
      str_tab =  " FROM (SELECT 
                           a.*,
                           IF(a.rels_total_quantity=0,
                                a.rels_comp_total_quantity,
                                100 * (IFNULL(a.rels_comp_total_quantity, 0)) / a.rels_total_quantity
                           ) AS progress
                         FROM accept_orders AS a 
                         WHERE a.target_date BETWEEN \"#{params[:start_target_date]}\" AND \"#{params[:end_target_date]}\"
                           AND a.invalid_flag_code IN (#{invalid_vals})
                   ) AS t "

      return str_cols, str_tab, str_vals
    end
    #から実装
    def set_target_date_to_where(tab, params, str_where)
    end
  end

  # linkage 下記をかえす
  #  table_name : "orders", "purchases"など関連取引テーブルのテーブル名
  #  id : 関連取引テーブルのid。受注から発注を作ったなら、発注データのID
  #  state_code : 関連テーブルの状態のコード値
  #  invalid_flag_code : 無効フラグ
  #  sign_type_code : 赤黒（あれば）
  #  target_date : 関連取引データの処理日
  #  input_date : 関連取引データの入力日
  #  created_at : 関連取引データの作成日時
  #  updated_at : 関連取引データの更新日時
  #
  def linkage
    rels = AcceptOrder.get_all_rels(params[:id])
    result = []
    
    rels.each do |rel|
      link = {'table_name' => rel.table_name, 'progress' => 0}
      if rel.record_id.to_i > 0
        class_name = rel.table_name.classify
        record = eval("#{class_name}.find(#{rel.record_id})").only_hashfy
        ['id', 
         'state_code',
         'invalid_flag_code',
         'sign_type_code',
         'target_date',
         'input_date',
         'created_at',
         'updated_at'].each do |val|
           link[val] = record[val] if record.include?(val)
        end
        #sale_type_codeとかshipping_type_codeとか
        base_name = rel.table_name.singularize
        link['trans_type_code'] = record[ base_name + '_type_code'] if record.include?(base_name + '_type_code');
        #自身のテーブル名がsale_id, purchase_idとか赤黒伝票が有る取引処理この値が0より大きかったら赤黒伝票とわかる
        link['parent_id'] = record[base_name + '_id'] if record.include?(base_name + '_id');
        # 各テーブルで固有の正規化
        eval("#{class_name}.linkage_standerdize(record, link)")
        if link['invalid_flag_code']==MCODE_FLAG_OFF
          tmp_total_quantity = rel.table_name=='purchases' ? record['stock_total_quantity'] : record['total_quantity']
          link['total_quantity']=tmp_total_quantity
          accept_order_total = rel.table_name=='sales' ? rel.total_quantity.to_f : rel.stock_total_quantity.to_f
          if link['state_code']==MCODE_STATUS2_COMP
            if accept_order_total == 0 #分母が0だったら
              link['progress'] = tmp_total_quantity==0 ? 100 : 50
            else
              sign = (rel.table_name=='restorations' && accept_order_total < 0) ? -1: 1
              link['progress'] = (tmp_total_quantity.to_f * sign / accept_order_total ) * 100
            end
            link['comp_quantity']=tmp_total_quantity
          end
        end
        #注文買取の時に使う
        if link['table_name']=='shippings' && link['invalid_flag_code']==MCODE_FLAG_OFF 
          link['details'] = ShippingDetail.find(:all, :conditions => [' shipping_id = ? ' , link['id'] ]).ext_hashfy
        end
      end
      result << link
    end
    respond_to do |format|
      format.ext_json do
        render :json => result.to_ext_json('linkages', nil)
      end
    end
  end
  
end
