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.utc record.date = time_now.new_offset(self.time_offset).strftime("%Y/%m/%d %w") if record.date.blank? end def update_work_times(work_times,store=true) work_times = work_times.to_a time_now = DateTime.now.utc 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.utc 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.utc 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.utc.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.utc.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.utc if time_now.new_offset(self.time_offset).strftime('%Y/%m/%d') != self.get_last_work_time.strftime('%Y/%m/%d') self.stop self.store end date_str = time_now.new_offset(self.time_offset).strftime("%Y/%m/%d %w") if self.date != date_str self.save end end end def start(offset=nil) self.time_offset = offset if offset self.check_and_store self.status = "working" time_now = DateTime.now.utc 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.utc if self.work_times.count % 2 == 1 self.work_times.push(time_now) end self.status = "stop" self.calc("work_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.utc 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 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 start_index = time_infos.count - 1 start_index -= (start_index % 2) time_infos = time_infos[start_index..-1].to_a if !(self.send("#{field_name}_changed?")) && time_infos.count != 1 return all_seconds end end time_infos.push(DateTime.now.utc) if (padding && time_infos.count % 2 == 1) 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 else break end 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 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.utc 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