Skip to content

Commit

Permalink
Merge pull request #296 from DC7806/feature/add_overtimes
Browse files Browse the repository at this point in the history
加班補休額度申請 (#272)
  • Loading branch information
Tsehau Chao authored Sep 5, 2019
2 parents 3a0b1ee + b9a3576 commit b429f52
Show file tree
Hide file tree
Showing 33 changed files with 651 additions and 180 deletions.
54 changes: 0 additions & 54 deletions app/controllers/backend/overtime_controller.rb

This file was deleted.

98 changes: 98 additions & 0 deletions app/controllers/backend/overtimes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# frozen_string_literal: true
class Backend::OvertimesController < Backend::BaseController
before_action :set_query_object, except: :statistics

def index
@users = User.all
end

def verify;end

def update
if current_object.update(resource_params)
params[:approve] ? approve : reject
else
respond_to do |f|
f.html { render action: :verify }
f.json
end
end
end

def add_leave_time
@leave_time = LeaveTime.new
end

def create_leave_time
params[:leave_time][:user_id] = current_object.user.id
@leave_time = LeaveTime.new(resource_params)
if @leave_time.save(resource_params)
action_success(verify_backend_overtime_path(current_object))
else
render :add_leave_time
end
end

def add_compensatory_pay
@overtime_pay = OvertimePay.new
end

def create_compensatory_pay
params[:overtime_pay][:user_id] = current_object.user.id
params[:overtime_pay][:overtime_id] = params[:id]
@overtime_pay = OvertimePay.new(resource_params)
if @overtime_pay.save(resource_params)
action_success(verify_backend_overtime_path(current_object))
else
render :add_overtime_pay
end
end

def statistics
search_params = params.fetch(:q, {})&.permit(:year_eq, :month_eq)
@q = Overtime.where(compensatory_type: 'pay', status: :approved).ransack(search_params)
@summary = @q.result
end

private

def resource_params
case action_name
when 'create' then params.require(:overtime).permit(:user_id, :hours, :start_time, :end_time, :description)
when 'update' then params.require(:overtime).permit(:comment)
when 'create_leave_time' then params.require(:leave_time).permit(:user_id, :overtime_id, :leave_type, :quota, :effective_date, :expiration_date, :remark)
when 'create_compensatory_pay' then params.require(:overtime_pay).permit(:user_id, :overtime_id, :hour, :remark)
end
end

def set_query_object
@q = Overtime.ransack(search_params)
end

def search_params
@search_params = params.fetch(:q, {})&.permit(
:s, :status_eq, :end_time_lteq, :start_time_gteq, :compensatory_type_eq)
end

def collection_scope
@q.result.preload(:user)
end

def approve
if current_object.pending?
current_object.approve!(current_user)
action_success
else
action_fail t('warnings.not_verifiable'), :verify
end
end

def reject
if current_object.pending? or current_object.approved?
current_object.reject!(current_user)
action_success
else
action_fail t('warnings.not_verifiable'), :verify
end
end
end
34 changes: 0 additions & 34 deletions app/controllers/overtime_controller.rb

This file was deleted.

66 changes: 66 additions & 0 deletions app/controllers/overtimes_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
class OvertimesController < BaseController
include Selectable

def index
@q = current_user.overtimes.order(created_at: :desc).ransack(search_params)
@current_collection = @q.result.page(params[:page])
@current_collection = Kaminari.paginate_array(@current_collection.first(5)).page(params[:page]) unless params[:q].present?
end

def new
@current_object = collection_scope.new
end

def create
@current_object = collection_scope.new(resource_params)
if @current_object.save
action_success
else
render action: :new
end
end

def update
if current_object.canceled?
action_fail t('warnings.not_cancellable'), :edit
else
current_object.assign_attributes(resource_params)
if !current_object.changed?
action_fail t('warnings.no_change'), :edit
elsif current_object.revise!
action_success
else
render action: :edit
end
end
end

def cancel
if current_object.may_cancel?
current_object.cancel!
@actions << :cancel
action_success
elsif current_object.approved?
action_fail t('warnings.already_happened'), :index
else
action_fail t('warnings.not_cancellable'), :index
end
end

private

def resource_params
params.require(:overtime).permit(
:start_time, :end_time, :description, :compensatory_type
)
end

def collection_scope
current_user.overtimes
end

def search_params
@search_params = params.fetch(:q, {})&.permit(
:status_eq, :end_time_lteq, :start_time_gteq, :compensatory_type_eq)
end
end
17 changes: 17 additions & 0 deletions app/helpers/backend/overtimes_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true
module Backend
module OvertimesHelper
def overtime_submit_disabled?
return unless current_object.pay?
!current_object.may_approve? || current_object.overtime_pay&.hour.nil?
end

def render_append_hours_options
if current_object.may_approve? && current_object.leave?
link_to t("title.backend/overtimes.append_quota"), add_leave_time_backend_overtime_path, class: 'btn btn-warning'
elsif current_object.may_approve? && current_object.pay?
link_to t("title.backend/overtimes.append_overtime_pay"), add_compensatory_pay_backend_overtime_path, class: 'btn btn-warning'
end
end
end
end
77 changes: 55 additions & 22 deletions app/models/overtime.rb
Original file line number Diff line number Diff line change
@@ -1,61 +1,94 @@
# frozen_string_literal: true
class Overtime < ApplicationRecord
include AASM
include SignatureConcern

enum status: Settings.overtimes.statuses
enum compensatory_type: Settings.overtimes.compensatory_types

belongs_to :user
validates :description, :start_time, :end_time, presence: true
belongs_to :manager, class_name: 'User', foreign_key: 'manager_id'

has_one :overtime_pay

validates :description, :start_time, :end_time, :compensatory_type, presence: true
validate :hours_should_be_positive_integer
validate :time_overlapped

before_validation :assign_hours
enum status: Settings.leave_applications.statuses

aasm column: :status, enum: true do
state :pending, initial: true
state :approved
state :rejected
state :canceled

event :approve, after_commit: :create_leave_time do
event :approve, before: proc { |manager| sign(manager) } do
transitions to: :approved, from: :pending
end

event :reject do
event :reject, before: proc { |manager| sign(manager) } do
transitions to: :rejected, from: %i(pending approved)
end

event :revise do
transitions to: :pending, from: %i(pending approved)
transitions to: :pending, from: %i(pending)
end

event :cancel do
transitions to: :canceled, from: :pending
transitions to: :canceled, from: :approved, unless: :happened?
transitions to: :canceled, from: %i(pending approved)
end
end
private

def happened?
Time.current > self.start_time
def leave_time_params
{
user_id: self.user_id,
leave_type: 'bonus',
quota: self.hours,
effective_date: self.start_time.to_date,
expiration_date: self.start_time.to_date.end_of_year
}
end

def auto_calculated_minutes
return @minutes = 0 unless start_time && end_time
@minutes = Daikichi::Config::Biz.within(start_time, end_time).in_minutes
ransacker :year do
Arel.sql('extract(year from created_at)')
end

ransacker :month do
Arel.sql('extract(month from created_at)')
end

private

def assign_hours
self.hours = self.send(:auto_calculated_minutes) / 60
return unless start_time && end_time
self.hours = ((end_time - start_time) / 3600).to_i
end

def hours_should_be_positive_integer
return if self.errors[:start_time].any? or self.errors[:end_time].any?
errors.add(:end_time, :not_integer) if (@minutes % 60).nonzero? || !self.hours.positive?
errors.add(:start_time, :should_be_earlier) unless self.end_time > self.start_time
return if errors.any?
errors.add(:end_time, :not_integer) unless ((end_time - start_time).to_i % 3600).zero?
errors.add(:start_time, :should_be_earlier) unless end_time > start_time
end

def time_overlapped
return if errors.any?
overlapped_records = Overtime.where('(start_time, end_time) OVERLAPS (?, ?)', start_time , end_time).where.not(id: self.id)
return unless overlapped_records.any?
time_overlapped_errors(overlapped_records)
end

def create_leave_time
if Date.today.month > 10
LeaveTime.create(leave_type: 'bonus', quota: hours, usable_hours: hours, used_hours: 0, locked_hours: 0, user_id: user_id, effective_date: Date.today, expiration_date: Date.today.end_of_year + 3.months, remark: "申請加班補休核准")
else
LeaveTime.create(leave_type: 'bonus', quota: hours, usable_hours: hours, used_hours: 0, locked_hours: 0, user_id: user_id, effective_date: Date.today, expiration_date: Date.today.end_of_year, remark: "申請加班補休核准")
def time_overlapped_errors(records)
url = Rails.application.routes.url_helpers
records.each do |record|
next if record.rejected? || record.canceled?
errors.add(:base,
I18n.t(
'activerecord.errors.models.overtime.attributes.base.time_range_overlapped',
start_time: record.start_time.to_formatted_s(:month_date),
end_time: record.end_time.to_formatted_s(:month_date),
link: url.overtime_path(id: record.id))
)
end
end
end
4 changes: 4 additions & 0 deletions app/models/overtime_pay.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class OvertimePay < ApplicationRecord
belongs_to :overtime
belongs_to :user
end
Loading

0 comments on commit b429f52

Please sign in to comment.