module CommLogistics::Tools
  # edited by shimizu
  class CalcDuty
    include Comm::Const::MasterCode
    # 税金を計算するメソッド
    # *引数 
    #  price   : 入力数値
    #  options : 丸め設定 {:duty_rate => 税率, :fraction_method_code => 切り捨て／切り上げ／四捨五入, :frac_digit_code => 円未満／十円未満／百円未満}
    #
    # *返却値
    #  指定桁で丸められた数値
    def self.calc_decimal_duty(price, options)
      rate = options[:duty_rate]
      if rate.blank? || rate==0
        return 0
      else
        return self.calc_decimal(price, options)
      end
    end

    # 小数点以下を処理するメソッド
    # *引数 
    #  price   : 入力数値
    #  options : 丸め設定 {:duty_rate => 税率, :fraction_method_code => 切り捨て／切り上げ／四捨五入, :frac_digit_code => 円未満／十円未満／百円未満}
    #
    # *返却値
    #  指定桁で丸められた数値
    def self.calc_decimal(price, options)
      Rails.logger.debug("calc_decimal input :"+price.to_s)
      
      rate = options[:duty_rate]  #税率
      fraction_method = options[:fraction_method_code] #小数以下切り捨て、切り上げ、四捨五入
      frac_digit = options[:frac_digit_code]  #円未満、十円未満、百円未満
      
      #とりあえず、正の値にする
      if price < 0
        minus_flag = true
        price = price * -1
      end
      #消費税を出す
      if rate > 0
        price = price * 0.01 * rate
      end
      # 1/10/100で割る
      tmp_decimal = price / frac_digit
      Rails.logger.debug("calc_decimal intermediate :"+tmp_decimal.to_s)
      #端数処理
      case fraction_method
      when MCODE_FRACTION_METHOD_FLOOR
        tmp_decimal = tmp_decimal.truncate
      when MCODE_FRACTION_METHOD_CEIL
        tmp_decimal = tmp_decimal.ceil
      when MCODE_FRACTION_METHOD_ROUND
        tmp_decimal = tmp_decimal.round
      else
        tmp_decimal = tmp_decimal.round
      end
      # マイナスだったら元に戻す。
      if minus_flag
        tmp_decimal = tmp_decimal * frac_digit * -1
      else
        tmp_decimal = tmp_decimal * frac_digit
      end
      Rails.logger.debug("calc_decimal output :"+ tmp_decimal.to_s)
      return tmp_decimal
    end
    
    # 単価の小数点以下を処理するメソッド
    # *引数 
    #  value : 単価
    #  options : {:unit_price_fraction_method_code => 切り捨て／切り上げ／四捨五入}
    #
    # *返却値
    #  小数以下が処理された単価
    def self.round_price(value, options)
      if options[:unit_price_fraction_method_code] and options[:unit_price_fraction_method_code] > 0
        return self.calc_decimal(value, {:duty_rate=> 0, :fraction_method_code=>options[:unit_price_fraction_method_code], :frac_digit_code=>1})
      else
        return value;
      end
    end
    # 単価×数量の計算結果を丸めるメソッド
    # *引数
    #  price : 単価
    #  quantity : 数量
    #  options : {:unit_price_fraction_method_code => 切り捨て／切り上げ／四捨五入,
    #             :price_fraction_method_code => 切り捨て／切り上げ／四捨五入}
    #
    # *返却値
    #  小数以下が丸められた 単価×数量の値
    def self.calc_sub_total(price, quantity, options)
      tmp_result = self.round_price(price, options) * quantity
      if options[:price_fraction_method_code] and options[:price_fraction_method_code] > 0
        return self.calc_decimal(tmp_result, {:duty_rate => 0, :fraction_method_code=>options[:price_fraction_method_code], :frac_digit_code=>1})
      else
        return tmp_result
      end
    end
    
    # 合計金額を計算するメソッド
    # *引数 
    #  records : [{'price'=>数値, 'quantity'=>数値,.....}] 単価と数量のハッシュを持つ配列
    #  options : {:unit_price_fraction_method_code => 切り捨て／切り上げ／四捨五入, :price_fraction_method_code => 切り捨て／切り上げ／四捨五入}
    #
    # *返却値
    #  伝票合計金額合計値
    def self.calc_total(records, options, ignore_quantity=false)
      total = 0
      records.each do |rec|
        total += self.calc_sub_total(rec['price'].to_f, ignore_quantity ? 1 : rec['quantity'].to_i, options)
      end
      return total
    end
    
    # 消費税を計算するメソッド
    # *引数
    #  records : [{'price'=>数値, 'quantity'=>数値,.....}] 単価と数量のハッシュを持つ配列
    #  options : { :unit_price_fraction_method_code => 単価の丸め 切り捨て／切り上げ／四捨五入, 
    #              :price_fraction_method_code => 単価×数量の計算結果の丸め 切り捨て／切り上げ／四捨五入,
    #              :duty_type_code => 0(非課税)/1(課税)
    #              :price_duty_type_code => 0(税抜き)/1(税込み)
    #              :duty_calc_type_code => 1(伝票合計)/2(伝票明細)/3(請求書合計)/4(その他)
    #              :fraction_method_code => 切り捨て／切り上げ／四捨五入
    #              :frac_digit_code => 円未満／十円未満／百円未満
    #              :duty_rate => 消費税率 5
    #            }
    #
    # *返却値
    #  伝票の消費税額
    def self.calc_total_duty(records, options, ignore_quantity=false)
      total_duty=0
      #課税で、税抜きの場合消費税を計算する。
      if options[:duty_type_code]==MCODE_DUTY_TYPE_CODE_ON && options[:price_duty_type_code]==MCODE_PRICE_DUTY_TYPE_EXC
        #伝票合計
        if options[:duty_calc_type_code]==MCODE_CALC_DUTY_SLIP_TOTAL
          total_duty = self.calc_decimal_duty(self.calc_total(records, options, ignore_quantity), options)
        #伝票明細合計
        elsif options[:duty_calc_type_code]==MCODE_CALC_DUTY_SLIP_DETAIL then
          records.each do |rec|
            total_duty += self.calc_decimal_duty(self.calc_sub_total(rec['price'].to_f, ignore_quantity ? 1 : rec['quantity'].to_i, options), options)
          end
        #elseは請求書合計だけど、計算する必要ない
        end
      end
      return total_duty
    end
    
  end
end
