5xRuby/daikichi

View on GitHub
app/services/leave_time_builder.rb

Summary

Maintainability
A
2 hrs
Test Coverage
# frozen_string_literal: true
class LeaveTimeBuilder
  MONTHLY_LEAVE_TYPES = Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'monthly' }
  WEEKLY_LEAVE_TYPES = Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'weekly' }
  JOIN_DATE_BASED_LEAVE_TYPES = Settings.leave_types.to_a.select { |lt| lt.second['creation'] == 'join_date_based' }
  JOIN_DATE_BASED_LEED_DAY = Settings.leed_days.join_date_based.day

  def initialize(user)
    @user = user
  end

  def automatically_import(by_assign_date: false)
    monthly_import by_assign_date: by_assign_date
    join_date_based_import by_assign_date: by_assign_date
    weekly_import by_assign_date: by_assign_date
  end

  def join_date_based_import(by_assign_date: false, prebuild: false)
    return create_leave_time('personal', 2920, @user.join_date, @user.join_date.next_year) if @user.role == 'contractor'
    JOIN_DATE_BASED_LEAVE_TYPES.each do |leave_type, config|
      build_join_date_based_leave_types(leave_type, config, prebuild, by_assign_date)
    end
  end

  def monthly_import(by_assign_date: false, prebuild: false)
    return if @user.role == 'contractor'
    MONTHLY_LEAVE_TYPES.each do |leave_type, config|
      build_monthly_leave_types(leave_type, config, prebuild, by_assign_date)
    end
  end

  def weekly_import(by_assign_date: false, prebuild: false)
    return if @user.role == 'contractor'
    return unless by_assign_date || Time.current.monday?
    date = Time.zone.today + 4.weeks
    WEEKLY_LEAVE_TYPES.each do |leave_type, config|
      build_weekly_leave_types(leave_type, config, date, by_assign_date)
    end
  end

  private

  def build_join_date_based_leave_types(leave_type, config, prebuild, build_by_assign_date = false)
    return unless user_can_have_leave_type?(@user, config)
    quota = extract_quota(config, @user, prebuild: prebuild)
    if build_by_assign_date
      join_date_based_by_assign_date(leave_type, quota)
    else
      join_anniversary = @user.next_join_anniversary
      expiration_date = join_anniversary.next_year - 1.day
      create_leave_time(leave_type, quota, join_anniversary, expiration_date)
    end
  end

  def join_date_based_by_assign_date(leave_type, quota)
    if @user.assign_date < @user.join_date
      date = @user.join_date
      expiration_date = date.next_year - 1.day
    else
      date = @user.assign_date
      expiration_date = if date.month > @user.join_date.month or (date.month == @user.join_date.month and date.day >= @user.join_date.day)
                          Date.parse("#{date.next_year.year}/#{@user.join_date.month}/#{@user.join_date.day}") - 1.day
                        else
                          Date.parse("#{date.year}/#{@user.join_date.month}/#{@user.join_date.day}") - 1.day
                        end
    end
    return if @user.assign_date > Time.current.to_date.next_year
    while date <= Time.zone.now.to_date
      create_leave_time(leave_type, quota, date, expiration_date)
      date = expiration_date + 1.day
      expiration_date = date.next_year - 1.day
    end
    create_leave_time(leave_type, quota, date, expiration_date) if Time.zone.now.to_date + JOIN_DATE_BASED_LEED_DAY >= date or @user.join_date + 1.year >= Time.zone.now.to_date
  end

  def build_monthly_leave_types(leave_type, config, prebuild, build_by_assign_date = false)
    quota = extract_quota(config, @user, prebuild: prebuild)
    if build_by_assign_date
      date = @user.assign_date >= @user.join_date ? @user.assign_date : @user.join_date
      while date <= Time.zone.now.to_date
        expiration_date = date.end_of_month
        create_leave_time(leave_type, quota, date, expiration_date)
        date = date.next_month.beginning_of_month
      end
    else
      @effective_date  = prebuild ? Time.zone.today.next_month.beginning_of_month : Time.zone.today
      @expiration_date = prebuild ? Time.zone.today.next_month.end_of_month : Time.zone.today.end_of_month
      create_leave_time(leave_type, quota, @effective_date, @expiration_date)
    end
  end

  def build_weekly_leave_types(leave_type, config, date, build_by_assign_date)
    quota = extract_quota(config, @user)
    if build_by_assign_date
      effective_date = @user.assign_date
      expiration_date = @user.assign_date.end_of_week
      create_leave_time(leave_type, quota, effective_date, expiration_date)
      create_leave_time(leave_type, quota, effective_date.beginning_of_week + 1.week, expiration_date + 1.week)
      create_leave_time(leave_type, quota, effective_date.beginning_of_week + 2.week, expiration_date + 2.week)
      create_leave_time(leave_type, quota, effective_date.beginning_of_week + 3.week, expiration_date + 3.week)
    else
      effective_date = date.beginning_of_week
      expiration_date = date.end_of_week
      create_leave_time(leave_type, quota, effective_date, expiration_date)
    end
  end

  def create_leave_time(leave_type, quota, effective_date, expiration_date)
    @user.leave_times.create(
      leave_type: leave_type,
      quota: quota,
      usable_hours: quota,
      used_hours: 0,
      effective_date: effective_date,
      expiration_date: expiration_date
    )
  end

  def extract_quota(config, user, prebuild: false)
    return config['quota'] * 8 if config['quota'].is_a? Integer
    seniority = prebuild ? user.seniority(user.next_join_anniversary) : user.seniority
    return config['quota']['maximum_quota'] if seniority >= config['quota']['maximum_seniority']
    config['quota']['values'][seniority.to_s.to_sym] * 8
  end

  def user_can_have_leave_type?(user, config)
    return true if config['quota'].is_a? Integer
    config['quota']['type'] != 'seniority_based' || user.fulltime?
  end
end