module CommLogistics::Modules::MngStock
  include CommLogistics::Const::Code
  include CommLogistics::Const::Error
  include CommLogistics::Modules::ErrorStore
  
  # stock更新
  def update_stock(main, details, calc_type)
    logger.debug(["update_stock","main:#{main.inspect}","details:#{details.inspect}","calc_type:#{calc_type}"].join("\n\t"))
    customer_id, warehouse_id = get_ids(main)
    
    details.each do |params|
      quantity = get_quantity(params, calc_type)
      stock_params = make_stock_params(customer_id, warehouse_id, params)
      
      # (+) target stock  (if calc type sub (-) target stock)
      target_stock = Stock.out_search(stock_params).first
      unless target_stock
        if quantity < 0 #calc_type == CALC_SUB 貸出先でいきなり売上赤伝票を作るときを考慮する
          logger.info(">>> no stock to sub:\n\t"+stock_params.inspect)
          #製品のIDと名前を追加する-----------
          rmsg = ["o 製品ID:"+ stock_params['product_id'].to_s]
          pd = Product.find(stock_params['product_id'])
          if pd and pd.disp_name
            rmsg << "【"+pd.disp_name+"】"
          end
          #製品のIDと名前を追加する---ここまで--------
          raise UserOperationError, LOEMJ0002 + LOEMD0002 + '<br>' + rmsg.join(" ")
        end
        target_stock = Stock.new(stock_params)
      end
      
      short_flg = (params["stock_type_code"] == MCODE_STOCK_TYPE_SHRT) ? true : false
      unless target_stock.add_quantity(quantity, short_flg)
        raise LOEMJ0002 + LOEMD0003
      end
      
      unless target_stock.save
        raise EMJ0001 + EMD0001
      end
      save_target_stock(target_stock, stock_params, params, quantity, false)
      logger.debug(["update_stock","target stock:#{target_stock.inspect}"].join("\n\t"))
    end
    check_warning
    return true
  end
  
  # 自社"倉庫"用
  # out_stockはshippingsとrestorationsで自社管理倉庫なのに、出荷対象、返却対象になっているときにtrue
  def update_own_stock(main, details, calc_type, out_stock=false, only_avail=false)
    logger.debug(["update_own_stock","main:#{main.inspect}","details:#{details.inspect}","calc_type:#{calc_type}"].join("\n\t"))
    customer_id, warehouse_id = get_ids(main)
    
    details.each do |params|
      quantity  = get_quantity(params, calc_type)
      stock_params = make_stock_params(customer_id, warehouse_id, params, (out_stock ? false : true) )
      
      # (+) own stock  (if calc type sub (-) own stock)
      own_stock = Stock.own_search(stock_params).first
      unless own_stock
        #if calc_type == CALC_SUB
        if quantity < 0 #calc_type == CALC_SUB 仕入伝票で検品が「未」の状態でstocksテーブルに候補が無い場合で更新すると、エラーになるから、暫定的にこうしておく。
          logger.info(">>> no stock to sub:\n\t"+stock_params.inspect)
          #製品のIDと名前を追加する-----------
          rmsg = ["o 製品ID:"+ stock_params['product_id'].to_s]
          pd = Product.find(stock_params['product_id'])
          if pd and pd.disp_name
            rmsg << "【"+pd.disp_name+"】"
          end
          #製品のIDと名前を追加する---ここまで--------
          raise UserOperationError, LOEMJ0002 + LOEMD0002 + '<br>' + rmsg.join(" ")
        end
        own_stock = Stock.new(stock_params)
      end
      
      if only_avail
        add_result = own_stock.add_quantity_avail(quantity)
      else
        add_result = own_stock.add_quantity(quantity, false)
      end
      unless add_result
        raise LOEMJ0002 + LOEMD0003
      end
      
      unless own_stock.save
        raise EMJ0001 + EMD0001
      end
      save_target_stock(own_stock, stock_params, params, quantity, true)
      logger.debug(["update_own_stock","target stock:#{own_stock.inspect}"].join("\n\t"))
    end
    check_warning
    return true
  end
  def save_target_stock(stock, stock_params, params, quantity, own_flag)
  end
  def check_warning
  end
  # utilities for model
  def get_ids(params)
    customer_id = get_value_by_name(params, :customer_id)
    warehouse_id = get_value_by_name(params, :warehouse_id)
    return customer_id, warehouse_id
  end
  
  def status_complete?(params)
    state = get_value_by_name(params, :state_code)
    return CommLogistics::Tools::Status.complete?(state, :state_code)
  end
  
  def own_supplier?(params)
    sid = get_value_by_name(params, :supplier_id)
    return Supplier.is_own?(sid)
  end
  
  def own_warehouse?(params)
    wid = get_value_by_name(params, :warehouse_id)
    return Warehouse.is_own?(wid)
  end
  
  def extract_lacking_params(container_hash, main)
    ['customer_id', 'warehouse_id', 'supplier_id'].each do |name|
      value = get_value_by_name(main, name)
      #logger.debug(["extract_lacking_params","value:#{value}","name:#{name}"].join("\n\t"))
      if value
        container_hash[name] = value
      end
    end
  end
  
  #== stockテーブル用パラメータ作成
  #  固有のエラーチェックなどがある場合は
  #  このmethodごと各モデルでoverrideしましょう
  #
  def get_details_params_for_stock(main, details, overwrite_params={})
    results = []
    update_params = {}
    extract_lacking_params(update_params, main)
    logger.debug(["MNG_STOCK : get_details_params_for_stock",
                  "extract_params : #{update_params.inspect}",
                  "details : #{details.inspect}"].join("\n\t"))
    update_params.update(overwrite_params)
    error_array=[]
    details.each do |params|
      #sales/purchase以外で非在庫管理製品があった場合はエラーを出力する
      unless params['stock_flag_code'] == MCODE_STOCK_FLAG_ON
        error_array << Product.find(params['product_id']).disp_name
        next
      end
      new_params = Marshal.load(Marshal.dump(params))
      new_params.update(update_params)
      results.push(new_params)
    end
    unless error_array.blank?
      #エラー
      msg = LOEMJ0002+LOEMD0020+error_array.join(', ')
      raise UserOperationError, msg
    end
    logger.debug(["get_details_params_for_stock",
                  "results : #{results.inspect}"].join("\n\t"))
    results
  end
  
protected
  def make_stock_params(customer_id, warehouse_id, detail_params, location_flag=false)
    # check parameters
    detail_table_name = self.class.name.underscore+'_details'
    ['product_id', 'ubd', 'quantity'].each do |col|
      if detail_params[col].blank?
        add_lack_msg(col, detail_table_name)
      end
    end
    ['lot_number', 'serial_number'].each do |col|
      if detail_params[col].nil?
        add_lack_msg(col, detail_table_name)
      end
    end
    raise_exception_with_any_error
    
    # create parameters
    params = {}
    stock_column = Stock.column_names
    excludes = ['id', 'created_at', 'updated_at']
    detail_params.each do |key, value|
      if stock_column.include?(key) && !excludes.include?(key)
        if key == 'ubd'
          value = get_valid_ubd(value)
        end
        #ロケーションを追加する
        if key == 'location_number' && !location_flag
          value = ''
        end
        params[key] = value
      end
    end
    #売上の赤から始まるときは、location_numberのkeyをそもそも持たないので、作ってあげる。
    unless params.key?('location_number')
      params['location_number']=''
    end
    params['existing_quantity'] = 0
    params['available_quantity'] = 0
    params['short_shipped_quantity'] = 0
    logger.debug(["make_stock_params","params:#{params.inspect}"].join("\n\t"))
    return params
  end
  
  def get_valid_ubd(value)
    if value.class == Date
      val = value.to_s
    else
      val = value.to_s.strip
      unless val =~ /^\d{4}[\/-]?\d{2}[\/-]?\d{2}$/
        raise "UBD is NOT correct : " + val
      end
    end
    return val
  end
  
  def get_quantity(params, calc_type)
    result = params['quantity'].to_i
    if calc_type == CALC_SUB
      result = (0 - result)
    end
    return result
  end
end
