#
# 棚卸原票
# 構造がOrder系とも取引系ともList系とも異なる中途半端な感じです
#
class InventoriesController < CommLogistics::Base::Controller::LogisticsController
  include CommLogistics::Modules::Print::Controller
  before_filter :set_controller_mode
  before_filter :fill_inventory_date, :only=>:ext_index
  def initialize
    @mcls = Inventory
  end
  # 在庫から棚卸原票データを作成
  def create
    inventory_date = params['inventory_date']
    #重複チェック
    inventory_date_d = Date.parse(inventory_date)
    if @mcls.inventory_dates.include?(inventory_date_d)
      raise 'inventory date is already registered :'+inventory_date
    end
    #つくる
    update_info_hash = {'inventory_date'=>inventory_date, 'deadline_date'=>inventory_date, 'sync_at'=>Time.now,
                        'note_1'=>'', 'note_2'=>'', 'note_3'=>'', 'note_4'=>'', 'note_5'=>''}
    own_warehouse_ids = Warehouse.own_ids
    @mcls.transaction do
      parent_ars = @mcls.collect_initial_inventory_infos(own_warehouse_ids)
      if parent_ars.length == 0
        raise "対象となるデータはありません"
      end
      parent_ars.each do |ar|
        parent_hash = ar.only_hashfy
        parent_hash.merge!(update_info_hash)
        fill_send_id(parent_hash)
        inventory_ar = @mcls.new(parent_hash)
        inventory_ar.save!
        refresh_child(inventory_ar, false)
      end
    end
    render :json => Comm::Tool::Json.result_json(true, '', {'inventory_date' => inventory_date})
  rescue => e
    error_out(e)
    render :json => Comm::Tool::Json.result_json(false, e.message)
  end
  #== 更新
  def update_records
    if @controller_mode == :customer
      customer_hash_ary = ActiveSupport::JSON.decode(params['records'])
      parent_hash_ary = expand_customer_hash_array(customer_hash_ary)
    else
      parent_hash_ary = ActiveSupport::JSON.decode(params['records'])
    end
    update_records_warehouse(parent_hash_ary)
  end
  def update_records_warehouse(parent_hash_ary)
    @mcls.transaction do
      parent_hash_ary.each do |ph|
        id = ph.delete('id')
        exclude_updating_keys(ph)
        inventory_ar = @mcls.find(id)
        inventory_ar.update_attributes!(ph)
      end
    end
    render :json => Comm::Tool::Json.result_json(true, '')
  rescue => e
    error_out(e)
    render :json => Comm::Tool::Json.result_json(false, e.message)
  end
#  NOTE_KEYS = ['note_1', 'note_2', 'note_3', 'note_4', 'note_5',]
  def exclude_updating_keys(parent_hash)
    parent_hash.delete('warehouse_id')
    parent_hash.delete('sync_at')
    parent_hash.delete('created_at')
    parent_hash.delete('updated_at')
    parent_hash.delete('tel')
    parent_hash.delete('fax')
    parent_hash.delete('inventory_date')
    #得意先の備考の変更はeditableがfalseのものをnilで送ってくるらしいので省く
#    NOTE_KEYS.each do |key|
#      unless parent_hash[key]
#        parent_hash.delete(key)
#      end
#    end
  end
  def update
    render :json => Comm::Tool::Json.result_json(false, 'Inner Error: Unsupported method.')
  end
  #== 削除
  def destroy
    target_ids = params['id_list'].split(",")
    @mcls.transaction do
      @mcls.delete(target_ids)
    end
    render :json => Comm::Tool::Json.result_json(true, '')
  rescue => e
    error_out(e)
    render :json => Comm::Tool::Json.result_json(false, e.message)
  end
  #== 再取得
  def refresh
    target_ids = params['id_list'].split(",")
    sync_at = Time.now
    update_info_hash = {'sync_at'=>Time.now, 'printed_at'=>nil, 'send_date'=>nil, 'receive_date'=>nil, 'close_date'=>nil}
    @mcls.transaction do
      fail_id_array = []
      target_ids.each do |id|
        inventory_ar = @mcls.find(id)
        parent_ars = @mcls.collect_inventory_info(inventory_ar.warehouse_id, inventory_ar.customer_id, inventory_ar.supplier_id)
        if parent_ars.length == 0
          raise "不明なエラーです。担当者にお問い合わせください。ID:"+id.inspect
        end
        parent_hash = parent_ars.first.only_hashfy
        if parent_hash['total_quantity'] == 0
          fail_id_array << id
          next
        end
        if fail_id_array.length > 0
          next
        end
        parent_hash = parent_ars.first.only_hashfy
        parent_hash.merge!(update_info_hash)
        fill_send_id(parent_hash)
        inventory_ar.update_attributes!(parent_hash)
        refresh_child(inventory_ar)
      end
      if fail_id_array.length > 0
        raise "以下IDの現在庫が確認できません。<br>現在庫数や得意先を確認してください。<br>"+fail_id_array.join(', ')
      end
    end
    render :json => Comm::Tool::Json.result_json(true, '')
  rescue => e
    error_out(e)
    render :json => Comm::Tool::Json.result_json(false, e.message)
  end
  #== PDF出力
  def print_sheet
    # 棚卸原票PDFのrecord_listのデータ形式
    # params[:record_list] = {supplier_id => {send_customer_id => データ}}
    # StocksCustomersDetailsPdfのロジックを使いまわせるように整形します
    params[:show_all]=true
    params[:record_list]={}
    supplier_id_list = []
    customer_id_list = []
    inventories_ary = get_record_list.ext_hashfy({:disp => {:disp_keys => params[:print_disp_keys]}})
    inventories_ary.each do |iv|
      supplier_id = iv['supplier_id'].to_i
      send_customer_id = iv['send_customer_id'].to_i
      unless params[:record_list].include?(supplier_id)
        params[:record_list][supplier_id] = {}
        supplier_id_list << supplier_id
      end
      unless params[:record_list][supplier_id].include?(send_customer_id)
        params[:record_list][supplier_id][send_customer_id] = []
        customer_id_list << send_customer_id
      end
      params[:record_list][supplier_id][send_customer_id] << iv
    end
    params[:supplier_id] = supplier_id_list.join(',')
    params[:id_list] = customer_id_list.join(',')
    #ここでend_target_dateをセットしておかないとstocks_customer_detailsのprint_sheetでバグル。
    params[:end_target_date]= params[:inventory_date]
    print_sheet_base(InventoryPDF)
  end
  # PDF出力用検索
  def get_record_list
    ss = InventoriesSheetSearch.new
    ars = ss.search(FLAG_ON, InventoryDetail, [], params)
    return ars
  end
  class InventoriesSheetSearch < Comm::Tool::SqlSearch
    def get_columns_and_tables(tab, join_lists, params, str_vals)
      id_list_str = params['id_list']
      str_cols = ' i.warehouse_id,
                   i.send_customer_id,
                   i.customer_id,
                   i.supplier_id,
                   i.deadline_date,
                   i.inventory_date,
                   i.sync_at,
                   id.inventory_id,
                   id.product_category_id,
                   id.product_set_id,
                   id.product_id,
                   id.lot_number,
                   id.serial_number,
                   id.ubd,
                   id.existing_quantity'
      str_tab = " FROM inventory_details AS id
                  LEFT JOIN inventories AS i 
                  ON id.inventory_id = i.id 
                  LEFT JOIN master_app_production.products AS p 
                  ON id.product_id = p.id 
                  WHERE i.id in (#{id_list_str})
                  /*ORDER BY i.supplier_id, i.send_customer_id, i.customer_id, i.warehouse_id,*/ 
                  ORDER BY i.supplier_id, FIELD(i.id, #{id_list_str}), 
                           id.product_category_id, id.product_set_id, CAST(p.spec1 AS UNSIGNED), CAST(p.spec2 AS DECIMAL(6,3)), id.ubd "
      return str_cols, str_tab, str_vals
    end
  end
  # PDF出力
  class InventoryPDF < StocksCustomersDetailsController::StocksCustomersDetailsPdf
    def initialize(params, mcls)
      super
      @page_total_by_warehouses = true
      @pdf_basename = 'inventory'
      @update_time_column_symbol = :printed_at
      @cancel_auto_update_time = true
      @cancel_head = false
      @blank_head = params.include?('blank_head') and params['blank_head']
    end
    def start_of_customer(pdata, page, cnt, customer_id)
      # 表紙空の設定ナド
      if @blank_head
        @header_page_num = page
        @warehouse_index = 0
        pdata[@header_page_num] ||= {}
        pdata[@header_page_num][:page_info] = {:head_page => true}
        @start_page_index += 1
        page += 1
      else
        page, cnt = super
      end
      @tmp_inventory_date = []
      return page, cnt
    end
    def end_of_warehouse(pdata, rec, page, cnt)
      #ヘッダページの締切り表示
      deadline_date = Date.parse(rec['deadline_date'])
      if !@tmp_deadline_date || (@tmp_deadline_date < deadline_date)
        @tmp_deadline_date = deadline_date
      end
      unless @tmp_inventory_date.include?(rec['inventory_date'].to_s)
        @tmp_inventory_date.push(rec['inventory_date'].to_s)
      end
      #印刷日時更新
      ar = @mcls.find(rec['inventory_id'])
      unless ar.update_attribute(@update_time_column_symbol, @record_update_time)
        raise 'Time Logging Failed'
      end
      super
    end
    def end_of_customer(pdata, page, cnt)
      pdata[@header_page_num]['deadline_month'] = @tmp_deadline_date.month
      pdata[@header_page_num]['deadline_day'] = @tmp_deadline_date.day
      pdata[@header_page_num]['deadline_date'] = @tmp_deadline_date.jpn_wday
      pdata[@header_page_num]['inventory_date'] = Date.parse(@tmp_inventory_date[0]).strftime("%m/%d") if @tmp_inventory_date.length==1
      @tmp_deadline_date = nil
      super
    end
    # データ状態
    def count_to_next_record(pdata, page, cnt, rec, next_page=false)
      sync = rec['sync_at']
      if sync.class == String
        sync = DateTime.parse(sync)
      end
      pdata[page]['sync_at'] = sync.strftime("%Y/%m/%d  %H:%M")
      super
    end
  end
protected
  def expand_customer_hash_array(customer_hash_ary)
    parent_hash_ary = []
    customer_hash_ary.each do |ch|
      ids = ch.delete('id_list').split(",")
      ids.each do |id|
        chash = ch.clone
        chash['id'] = id
        parent_hash_ary << chash
      end
    end
    return parent_hash_ary
  end
  def set_controller_mode
    @controller_mode = :warehouse
    if params.include?('customer') and params['customer']
      @controller_mode = :customer
    end
  end
  def fill_inventory_date
    if params['inventory_date'].blank?
      last_inventory_date = @mcls.last_inventory_date
      params['inventory_date'] = last_inventory_date
    end
  end
  def fill_send_id(parent_hash)
    if parent_hash['send_customer_id'].blank?
      parent_hash['send_customer_id'] = parent_hash['customer_id']
    end
  end
  def refresh_child(inventory_ar, clear_in_advance=true)
    if clear_in_advance
      inventory_ar.child_details.clear
    end
    child_ars = @mcls.collect_inventory_details_infos(inventory_ar.warehouse_id, inventory_ar.customer_id, inventory_ar.supplier_id)
    child_ars.each do |car|
      inventory_ar.child_details.create(car.only_hashfy)
    end
  end
  #ext_index向け
  def get_sql_search
    if @controller_mode == :warehouse
      ss = InventoriesWarehouseSearch.new
    else
      ss = InventoriesCustomerSearch.new
    end
    ss.non_table_columns = ['tel', 'fax']
    return ss
  end
  class InventoriesSearch < Comm::Tool::SqlSearch
  end
  class InventoriesWarehouseSearch < InventoriesSearch
    def get_columns_and_tables(tab, join_lists, params, str_vals)
      @table_alias = {'inventories'=>'i', 'customers'=>'c'}
      str_cols = " i.*, c.fax, c.tel "
      str_tab =  " FROM inventories AS i"
      str_tab << " JOIN master_app_production.customers AS c ON i.send_customer_id = c.id "
      return str_cols, str_tab, str_vals
    end
    def set_additional_where(str_where, params)
      add_str_where(str_where, " i.inventory_date = \'#{params['inventory_date']}\' ")
      if !params.include?('with_closed') or !(params['with_closed']=='true')
        add_str_where(str_where, " i.close_date IS NULL ")
      end
    end
  end
  class InventoriesCustomerSearch < InventoriesSearch
    def get_columns_and_tables(tab, join_lists, params, str_vals)
      @table_alias = {'inventories'=>'t', 'customers'=>'t'}
      if params.include?('with_closed') and params['with_closed']=='true'
        close_where_str = " "
      else
        close_where_str = " WHERE tmp.close_null_cnt != 0 "
      end
      str_cols = " * "
      str_tab =  " FROM (SELECT * FROM (SELECT 
                     GROUP_CONCAT(i.id) AS id_list,
                     COUNT(i.id) AS id_cnt,
                     i.send_customer_id, i.supplier_id, i.inventory_date, c.fax, c.tel,
                     SUM(i.total_quantity) AS total_quantity,
                     MAX(printed_at) AS printed_at,
                     SUM(printed_at IS NULL) AS printed_null_cnt,
                     MAX(sync_at) AS sync_at,
                     MAX(deadline_date) AS deadline_date,
                     SUM(deadline_date IS NULL) AS deadline_null_cnt,
                     IF(COUNT(DISTINCT(IFNULL(i.deadline_date,'9999-00-00'))) > 1, 'false', 'true') AS deadline_editable,
                     MAX(send_date) AS send_date,
                     SUM(send_date IS NULL) AS send_null_cnt,
                     IF(COUNT(DISTINCT(IFNULL(i.send_date,'9999-00-00'))) > 1, 'false', 'true') AS send_editable,
                     MAX(receive_date) AS receive_date,
                     SUM(receive_date IS NULL) AS receive_null_cnt,
                     IF(COUNT(DISTINCT(IFNULL(i.receive_date,'9999-00-00'))) > 1, 'false', 'true')  AS receive_editable,
                     MAX(close_date) AS close_date,
                     SUM(close_date IS NULL) AS close_null_cnt,
                     IF(COUNT(DISTINCT(IFNULL(i.close_date,'9999-00-00'))) > 1, 'false', 'true')  AS close_editable,
                     IF(COUNT(DISTINCT(i.note_1)) > 1, null, i.note_1) AS note_1,
                     IF(COUNT(DISTINCT(i.note_2)) > 1, null, i.note_2) AS note_2,
                     IF(COUNT(DISTINCT(i.note_3)) > 1, null, i.note_3) AS note_3,
                     IF(COUNT(DISTINCT(i.note_4)) > 1, null, i.note_4) AS note_4,
                     IF(COUNT(DISTINCT(i.note_5)) > 1, null, i.note_5) AS note_5,
                     MAX(i.created_at) AS created_at,
                     MAX(i.updated_at) AS updated_at
                   FROM inventories AS i 
                   JOIN master_app_production.customers AS c ON i.send_customer_id = c.id 
                   WHERE i.inventory_date = \'#{params['inventory_date']}\'
                   GROUP BY i.send_customer_id, i.inventory_date ) AS tmp #{close_where_str} ) AS t"
      return str_cols, str_tab, str_vals
    end
  end
end