441 lines
16 KiB
Ruby
441 lines
16 KiB
Ruby
class RulingTimerTemp
|
|
include Mongoid::Document
|
|
include Mongoid::Timestamps
|
|
field :status, type: String, default: "stop" # working, rest, stop
|
|
field :work_time_str, type: String, default: "00:00:00"
|
|
field :rest_time_str, type: String, default: "00:00:00"
|
|
field :all_work_times_seconds, type: Integer, default: 0
|
|
field :all_rest_times_seconds, type: Integer, default: 0
|
|
field :work_times, type: Array, default: []
|
|
field :rest_times, type: Array, default: []
|
|
field :sub_task_ids, type: Array, default: [] #store RulingTimerSubTask id
|
|
field :tasks, type: Array, default: [] #store name only
|
|
field :tasks_finished, type: Array, default: [] #store index only
|
|
field :summary, type: String, default: ""
|
|
field :time_offset, type: String, default: "+8"
|
|
field :events, type: Array, default: []
|
|
field :date, type: String, default: ""
|
|
belongs_to :user
|
|
before_create do |record|
|
|
time_now = DateTime.now.new_offset(0)
|
|
record.date = time_now.new_offset(self.time_offset).strftime("%Y/%m/%d %w") if record.date.blank?
|
|
end
|
|
after_save do
|
|
@work_times_exec = nil
|
|
@rest_times_exec = nil
|
|
end
|
|
def get_attrs(except_fields=[])
|
|
attrs = {}
|
|
self.fields.except(*(["_id","created_at","updated_at"] + except_fields)).each do |k, v|
|
|
if (v.options[:localize] rescue false)
|
|
attrs["#{k}_translations"] = self[k]
|
|
else
|
|
attrs[k] = self[k]
|
|
end
|
|
end
|
|
attrs
|
|
end
|
|
def update_work_times(work_times,store=true)
|
|
work_times = work_times.to_a
|
|
time_now = DateTime.now.new_offset(0)
|
|
self.date = time_now.new_offset(self.time_offset).strftime("%Y/%m/%d %w") if self.date.blank?
|
|
date_str = self.date.split(" ")[0]
|
|
work_times = work_times.to_a.map do |t|
|
|
if t.blank?
|
|
nil
|
|
else
|
|
DateTime.parse("#{date_str} #{t}#{self.time_offset}").utc
|
|
end
|
|
end
|
|
self.work_times = work_times
|
|
self.save if store
|
|
self.work_times
|
|
end
|
|
def fix_work_times(store=true)
|
|
time_now = DateTime.now.new_offset(0)
|
|
work_times_range = self.work_times.each_slice(2).to_a.map{|a,b| convert_datetime(a)..(b.nil? ? time_now : convert_datetime(b))}
|
|
work_times_range = eliminate_intersection(work_times_range)
|
|
new_work_times_range = merge_ranges(work_times_range.uniq).flat_map{|range| [range.first,range.last]}
|
|
new_work_times_range = new_work_times_range[0...-1] if new_work_times_range.last == time_now
|
|
self.work_times = new_work_times_range
|
|
self.calc("work_times",false,true)
|
|
self.work_time_str = transform_second_to_time(self.all_work_times_seconds)
|
|
self.save if store
|
|
self.work_times
|
|
end
|
|
def merge_work_times(new_work_times,store=true)
|
|
time_now = DateTime.now.new_offset(0)
|
|
work_times_range = self.work_times.each_slice(2).to_a.map{|a,b| convert_datetime(a)..(b.nil? ? time_now : convert_datetime(b))}
|
|
new_work_times_range = new_work_times.each_slice(2).to_a.map{|a,b| convert_datetime(a)..(b.nil? ? time_now : convert_datetime(b))}
|
|
work_times_range = eliminate_intersection(work_times_range)
|
|
new_work_times_range = eliminate_intersection(new_work_times_range)
|
|
new_work_times_range = work_times_range + new_work_times_range
|
|
new_work_times_range = eliminate_intersection(new_work_times_range).sort_by{|range| range.first.to_i}
|
|
new_work_times_range = merge_ranges(new_work_times_range.uniq).flat_map{|range| [range.first,range.last]}
|
|
new_work_times_range = new_work_times_range[0...-1] if new_work_times_range.last == time_now
|
|
self.work_times = new_work_times_range
|
|
self.calc("work_times",false,true)
|
|
self.work_time_str = transform_second_to_time(self.all_work_times_seconds)
|
|
self.save if store
|
|
self.work_times
|
|
end
|
|
def merge_ranges(ranges)
|
|
(0...(ranges.count)).each do |i|
|
|
next if ranges[i+1].nil?
|
|
if ranges[i].last == ranges[i+1].first
|
|
ranges[i+1] = (ranges[i].first .. ranges[i+1].last)
|
|
ranges[i] = nil
|
|
end
|
|
end
|
|
ranges.compact
|
|
end
|
|
def eliminate_intersection(times_range)
|
|
times_range = times_range.sort_by{|range| range.first.to_i}
|
|
times_range.each_with_index do |range,i|
|
|
next if range.nil?
|
|
intersects = times_range[i+1..-1].map{|r| range & r}
|
|
if intersects.compact.count != 0
|
|
intersects.each_with_index do |intersect,j|
|
|
next if intersect.nil?
|
|
if range.last > intersect.last #overlap all
|
|
times_range[i+1+j] = nil
|
|
else
|
|
if range.first == intersect.first
|
|
times_range[i] = nil
|
|
else
|
|
times_range[i] = (range.first..intersect.first)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
times_range.compact
|
|
end
|
|
def update_task_name(task_id,new_name)
|
|
idx = self.sub_task_ids.index(task_id)
|
|
self.tasks[idx] = new_name
|
|
self.save
|
|
end
|
|
def remove_task(task_id)
|
|
sub_task = RulingTimerSubTask.find(task_id) rescue nil
|
|
idx = self.sub_task_ids.index(task_id)
|
|
self.sub_task_ids.delete(task_id)
|
|
self.tasks.delete_at(idx)
|
|
self.tasks_finished = self.tasks_finished.to_a.map do |task_idx|
|
|
if task_idx == idx
|
|
nil
|
|
elsif task_idx > idx
|
|
task_idx - 1
|
|
else
|
|
task_idx
|
|
end
|
|
end.compact
|
|
self.save!
|
|
sub_task.stop if sub_task
|
|
end
|
|
def get_work_times(display_seond=false)
|
|
work_times = self.work_times.clone
|
|
if display_seond
|
|
time_format = "%H:%M:%S"
|
|
else
|
|
time_format = "%H:%M"
|
|
end
|
|
work_times.map!{|t| convert_datetime(t).new_offset(self.time_offset).strftime(time_format)}
|
|
end
|
|
def get_last_work_time
|
|
last_work_time = self.work_times.last
|
|
if last_work_time.nil?
|
|
last_work_time = DateTime.now.new_offset(0).new_offset(self.time_offset)
|
|
else
|
|
last_work_time = convert_datetime(last_work_time).new_offset(self.time_offset)
|
|
end
|
|
return last_work_time
|
|
end
|
|
def get_first_work_time
|
|
first_work_time = self.work_times.first
|
|
if first_work_time.nil?
|
|
first_work_time = DateTime.now.new_offset(0).new_offset(self.time_offset)
|
|
else
|
|
first_work_time = convert_datetime(first_work_time).new_offset(self.time_offset)
|
|
end
|
|
return first_work_time
|
|
end
|
|
def check_and_store
|
|
unless self.new_record?
|
|
time_now = DateTime.now.new_offset(0)
|
|
date_str = time_now.new_offset(self.time_offset).strftime("%Y/%m/%d %w")
|
|
if self.date != date_str
|
|
self.stop
|
|
self.store
|
|
end
|
|
end
|
|
end
|
|
def start(offset=nil)
|
|
self.time_offset = offset if offset
|
|
self.check_and_store
|
|
self.status = "working"
|
|
time_now = DateTime.now.new_offset(0)
|
|
self.date = time_now.new_offset(self.time_offset).strftime("%Y/%m/%d %w")
|
|
if self.work_times.count % 2 == 0
|
|
self.work_times.push(time_now)
|
|
end
|
|
if self.rest_times.count % 2 == 1
|
|
self.rest_times.push(time_now)
|
|
end
|
|
self.calc("work_times",false)
|
|
self.calc("rest_times",false)
|
|
self.work_time_str = transform_second_to_time(self.all_work_times_seconds)
|
|
self.rest_time_str = transform_second_to_time(self.all_rest_times_seconds)
|
|
self.save
|
|
self.start_all_task
|
|
return self.to_json
|
|
end
|
|
def reset_all(except_fields=[])
|
|
unless self.new_record?
|
|
change_fields = self.changes.except(*(except_fields.map{|f| f.to_s}))
|
|
change_fields.each do |k,v|
|
|
self.send("#{k}=",v[0])
|
|
end
|
|
end
|
|
end
|
|
def start_all_task
|
|
temp_task_ids = self.sub_task_ids
|
|
if self.tasks_finished.count != 0
|
|
temp_task_ids = temp_task_ids.select.with_index{|id,i| !(self.tasks_finished.include?(i))}
|
|
end
|
|
temp_tasks = RulingTimerSubTask.where(:id.in=>temp_task_ids).to_a
|
|
temp_tasks.each{|task| task.start}
|
|
end
|
|
def stop_all_task
|
|
temp_task_ids = self.sub_task_ids
|
|
if self.tasks_finished.count != 0
|
|
temp_task_ids = temp_task_ids.select.with_index{|id,i| !(self.tasks_finished.include?(i))}
|
|
end
|
|
temp_tasks = RulingTimerSubTask.where(:id.in=>temp_task_ids).to_a
|
|
temp_tasks.each{|task| task.stop}
|
|
end
|
|
def stop
|
|
time_now = DateTime.now.new_offset(0)
|
|
tmp_date = Date.parse(self.date.split(" ")[0])
|
|
time_now_date = time_now.new_offset(self.time_offset).to_date
|
|
@new_ruling_timer = nil
|
|
if tmp_date != time_now_date
|
|
push_time = tmp_date.to_datetime.new_offset(self.time_offset).end_of_day.new_offset(0)
|
|
need_create_history = true
|
|
else
|
|
push_time = time_now
|
|
need_create_history = false
|
|
end
|
|
field_name = nil
|
|
if self.work_times.count % 2 == 1
|
|
self.work_times.push(push_time)
|
|
field_name = "work_times"
|
|
end
|
|
if self.rest_times.count % 2 == 1
|
|
self.rest_times.push(push_time)
|
|
field_name = "rest_times"
|
|
end
|
|
if need_create_history && field_name
|
|
tmp_attrs = self.get_attrs(["work_time_str", "rest_time_str", "all_work_times_seconds", "all_rest_times_seconds", "work_times", "rest_times", "status"])
|
|
tmp_attrs["all_#{field_name}_seconds"] = 86400
|
|
tmp_attrs["#{field_name.singularize}_str"] = "24:00:00"
|
|
self.store
|
|
self.send("#{field_name}=", [time_now.new_offset(self.time_offset).beginning_of_day.new_offset(0), time_now])
|
|
((tmp_date + 1.day)...time_now_date).each do |d|
|
|
tmp_date_str = d.strftime('%Y/%m/%d %w')
|
|
begin_of_d = DateTime.parse(d.strftime("%Y/%m/%d 00:00:00#{self.time_offset}"))
|
|
end_of_d = begin_of_d.end_of_day
|
|
tmp_attrs[field_name] = [begin_of_d.new_offset(0), end_of_d.new_offset(0)]
|
|
tmp_attrs["date"] = tmp_date_str
|
|
RulingTimerHistory.create(tmp_attrs)
|
|
end
|
|
end
|
|
self.status = "stop"
|
|
self.calc("work_times",false)
|
|
self.calc("rest_times",false)
|
|
self.work_time_str = transform_second_to_time(self.all_work_times_seconds)
|
|
self.rest_time_str = transform_second_to_time(self.all_rest_times_seconds)
|
|
self.save
|
|
self.stop_all_task
|
|
return self.to_json
|
|
end
|
|
def rest
|
|
self.status = "rest"
|
|
time_now = DateTime.now.new_offset(0)
|
|
if self.work_times.count % 2 == 1
|
|
self.work_times.push(time_now)
|
|
end
|
|
if self.rest_times.count % 2 == 0
|
|
self.rest_times.push(time_now)
|
|
end
|
|
self.calc("work_times",false)
|
|
self.calc("rest_times",false)
|
|
self.save
|
|
self.stop_all_task
|
|
return self.to_json
|
|
end
|
|
def recalc_all
|
|
self.calc("work_times",false,true)
|
|
self.calc("rest_times",false,true)
|
|
self.work_time_str = transform_second_to_time(self.all_work_times_seconds)
|
|
self.rest_time_str = transform_second_to_time(self.all_rest_times_seconds)
|
|
self.save
|
|
return self.to_json
|
|
end
|
|
def to_json
|
|
self.calc("work_times")
|
|
self.calc("rest_times")
|
|
work_seconds = self.all_work_times_seconds
|
|
rest_seconds = self.all_rest_times_seconds
|
|
self.reset_all
|
|
return {"work" => work_seconds, "rest" => rest_seconds}
|
|
end
|
|
def get_infos
|
|
self.calc("work_times")
|
|
self.calc("rest_times")
|
|
self.work_time_str = transform_second_to_time(self.all_work_times_seconds)
|
|
self.rest_time_str = transform_second_to_time(self.all_rest_times_seconds)
|
|
self.reset_all([:work_time_str,:rest_time_str])
|
|
return {"work" => self.work_time_str, "rest" => self.rest_time_str}
|
|
end
|
|
def convert_datetime(time)
|
|
if time.class == Time
|
|
return time.to_datetime
|
|
elsif time.class == DateTime
|
|
return time
|
|
elsif time.class == String
|
|
return DateTime.parse(time)
|
|
else
|
|
return Time.at(time).to_datetime #time is seconds
|
|
end
|
|
end
|
|
def getPaddedComp(comp)
|
|
return ((comp.to_i < 10) ? ('0' + comp.to_s) : comp.to_s)
|
|
end
|
|
def self.getPaddedComp(comp)
|
|
return ((comp.to_i < 10) ? ('0' + comp.to_s) : comp.to_s)
|
|
end
|
|
def self.transform_second_to_time(seconds)
|
|
seconds = 0 if seconds.nil?
|
|
hour = 3600
|
|
minute = 60
|
|
total_hour = getPaddedComp(seconds / hour)
|
|
rest_seconds = seconds % hour
|
|
total_minute = getPaddedComp(rest_seconds / minute)
|
|
total_second = getPaddedComp(rest_seconds % minute)
|
|
return (total_hour + ":" + total_minute + ":" + total_second)
|
|
end
|
|
def transform_second_to_time(seconds)
|
|
seconds = 0 if seconds.nil?
|
|
hour = 3600
|
|
minute = 60
|
|
total_hour = getPaddedComp(seconds / hour)
|
|
rest_seconds = seconds % hour
|
|
total_minute = getPaddedComp(rest_seconds / minute)
|
|
total_second = getPaddedComp(rest_seconds % minute)
|
|
return (total_hour + ":" + total_minute + ":" + total_second)
|
|
end
|
|
def calc(field_name,padding=true,recalc=false)
|
|
time_infos = self.send(field_name).clone rescue []
|
|
record_field_name = "all_#{field_name}_seconds"
|
|
tmp_seconds = self.send(record_field_name)
|
|
all_seconds = 0
|
|
start_index = 0
|
|
if !recalc
|
|
all_seconds = tmp_seconds
|
|
if self.send("#{field_name}_changed?") || (time_infos.count % 2 == 1)
|
|
instance_variable_name = "@#{field_name}_exec"
|
|
instance_variable = instance_variable_get(instance_variable_name)
|
|
if instance_variable.nil?
|
|
instance_variable_set(instance_variable_name, true)
|
|
last_val = self.send("#{field_name}_was").to_a.last
|
|
if last_val
|
|
idx = time_infos.index(last_val)
|
|
if idx
|
|
start_index = idx + (idx % 2 == 0 ? 0 : 1)
|
|
time_infos = time_infos[start_index..-1]
|
|
end
|
|
end
|
|
else
|
|
all_seconds = 0 #recalc
|
|
end
|
|
else
|
|
return all_seconds
|
|
end
|
|
end
|
|
time_infos.push(DateTime.now.new_offset(0)) if (padding && time_infos.count % 2 == 1)
|
|
prev_t = nil
|
|
time_infos.each_with_index do |t,i|
|
|
if i % 2 == 0
|
|
next_t = time_infos[i+1]
|
|
if !next_t.nil?
|
|
all_seconds += ((convert_datetime(next_t) - convert_datetime(t)) * 1.day).round + ((prev_t && prev_t == t) ? 0.second : 1.second)
|
|
else
|
|
break
|
|
end
|
|
else
|
|
prev_t = t
|
|
end
|
|
end
|
|
self.send("#{record_field_name}=",all_seconds)
|
|
return all_seconds
|
|
end
|
|
def add_event(startt,endt,event)
|
|
self.events << {"start"=>startt,"end"=> endt,"event"=>event}
|
|
self.save
|
|
end
|
|
def delete_event(idx)
|
|
self.events.delete_at(idx)
|
|
self.save
|
|
end
|
|
def store
|
|
self.calc("work_times")
|
|
self.calc("rest_times")
|
|
self.work_time_str = transform_second_to_time(self.all_work_times_seconds)
|
|
self.rest_time_str = transform_second_to_time(self.all_rest_times_seconds)
|
|
fields = self.fields.except("_id","created_at","updated_at","status").keys
|
|
if self.all_work_times_seconds != 0 || self.all_rest_times_seconds != 0
|
|
ruling_timer_history = RulingTimerHistory.new
|
|
fields.each do |f|
|
|
field_name = f
|
|
if (self.fields[f].options[:localize] rescue false)
|
|
field_name = "#{f}_translations"
|
|
end
|
|
ruling_timer_history.send("#{field_name}=",self.send(field_name))
|
|
end
|
|
ruling_timer_history.date = self.get_first_work_time.new_offset(self.time_offset).strftime("%Y/%m/%d %w")
|
|
ruling_timer_history.user = self.user
|
|
ruling_timer_history.save
|
|
@timer_history = ruling_timer_history
|
|
end
|
|
available_locales = I18n.available_locales
|
|
not_reset_fields = ["time_offset","user_id","tasks_finished","sub_task_ids","tasks"]
|
|
fields.each do |f|
|
|
next if not_reset_fields.include?(f)
|
|
default_value = self.fields[f].options[:default] rescue nil
|
|
if (self.fields[f].options[:localize] rescue false)
|
|
field_name = "#{f}_translations"
|
|
self.send("#{f}_translations=",available_locales.map{|l| [l.to_s,default_value]}.to_h)
|
|
else
|
|
self.send("#{f}=",default_value)
|
|
end
|
|
end
|
|
if self.tasks_finished.count != 0
|
|
temp_task_ids = self.sub_task_ids.clone
|
|
temp_tasks = self.tasks.clone
|
|
temp_tasks_finished = self.tasks_finished.clone.sort.reverse
|
|
temp_tasks_finished.each do |idx|
|
|
temp_task_ids.delete_at(idx)
|
|
temp_tasks.delete_at(idx)
|
|
end
|
|
self.sub_task_ids = temp_task_ids
|
|
self.tasks = temp_tasks
|
|
self.tasks_finished = []
|
|
end
|
|
time_now = DateTime.now.new_offset(0)
|
|
self.created_at = time_now
|
|
self.updated_at = time_now
|
|
self.date = time_now.new_offset(self.time_offset).strftime("%Y/%m/%d %w")
|
|
self.save
|
|
end
|
|
end |