Skip to content

Instantly share code, notes, and snippets.

@christiangenco
Last active July 9, 2016 22:04
Show Gist options
  • Save christiangenco/31cea53929d74642e50b to your computer and use it in GitHub Desktop.
Save christiangenco/31cea53929d74642e50b to your computer and use it in GitHub Desktop.
process EMC timecards
require 'time'
class Float
def round_to(x)
(self * 10**x).round.to_f / 10**x
end
def ceil_to(x)
(self * 10**x).ceil.to_f / 10**x
end
def floor_to(x)
(self * 10**x).floor.to_f / 10**x
end
end
class Timeset
attr_accessor :timein, :timeout, :truncate
def initialize(timein="0:00", timeout="0:00", truncate=false)
self.timein = timein
self.timeout = timeout
self.truncate = truncate
end
def timein=(t)
#puts "parsing: #{t}"
@timein = Time.parse(t)
@timein = to_pm(@timein) if(@timein < Time.parse("9:00"))
end
def timeout=(t)
@timeout = Time.parse(t)
@timeout = to_pm(@timeout) if(@timeout < Time.parse("9:40"))
end
def to_pm(t)
t + 12 * 60 * 60
end
def truncate(t)
return t if !@truncate || t==nil
if t>Time.parse('3:00pm') && t<Time.parse('3:12pm')
t = Time.parse('3:00pm')
end
if t>Time.parse('8:00pm') && t<Time.parse('8:12pm')
t = Time.parse('8:00pm')
end
return t
end
def hours
timein, timeout = @timein, @timeout
timeout = truncate(timeout)
(timeout - timein)/3600.0
end
def total
hours
end
def timestring_helper(t)
t.strftime("%I:%M %p").to_s.downcase
end
def timestring(t) #time to string
return '' if t==nil
output = timestring_helper(t)
if(t != truncate(t))
output += '=>' + timestring_helper(truncate(t))
end
output
end
def to_s
"#{timestring(@timein)} to #{timestring(@timeout)} = %.2f" %hours
end
def to_html
"<tr style='color:blue;background-color:#BBF'><td align='right'>#{timestring(self.timein)}</td></tr><tr><td align='right' style='color:blue;background-color:#EED'>#{timestring(self.timeout)}</td><td style='color:black'><i>#{self.total.round_to(2)}</i></td></tr>"
end
end
class Day
attr_accessor :times
def initialize(times = [])
@times = times
end
def << timeset
times << Timeset.new(timeset[0],timeset[1])
end
def lunch
return 0.0 if times.size < 2
(@times[1].timein - @times[0].timeout)/3600
end
def total
t = 0.0
self.times.each do |ts|
t+=ts.total
end
t
end
def to_html
output = ""
self.times.each_with_index do |ts, i|
output += ts.to_html
end
output+="<tr><td style='background-color:#FCC'>Break<0.5hrs</td><td style='background-color:#FCC'><u>#{lunch.round_to(2)}</u></td></tr>" if lunch < 0.5 && lunch != 0.0
output+="<tr><td>Day total</td><td style='background-color:#CFC'><u>#{total.round_to(2)}</u></td></tr>"
output += ""
output
end
end
class Employee
attr_accessor :name, :weeks
def initialize(name="Employee",weeks=[[]])
self.name = name
self.weeks = weeks
end
def <<(day, week=1)
#puts "adding day: #{day}"
weeks[week] = [] unless weeks[week] #instantiate it if it's null
weeks[week] << day
end
def total(week)
t = 0.0
overtime = 0
self.weeks[week].each do |d|
t += d.total
end
overtime += t-40 if t>40
[t.to_f, overtime.to_f]
end
def employee_total
t = 0
overtime = 0
weeks.each_with_index{|w,i|
marginal_time, marginal_overtime = total(i)
t += marginal_time
overtime += marginal_overtime
}
return [t.to_f, overtime.to_f]
end
def to_html
output = "<h3>#{self.name}</h3>\n<table border='1px' width='210px' cellpadding='0' cellspacing='0'>\n"
self.weeks.each_with_index do |w, i|
w.each do |d|
output += "<tr>\n" + d.to_html + "\n</tr>\n"
end
total, overtime = total(i)
output += "<tr><td><b>Week Total</b></td><td style='background-color:#9F9'>#{total.round_to(2)}</td></tr>"
output += "<tr><td><b>Week Overtime</b></td><td style='background-color:#9F9'>#{overtime.round_to(2)}</td></tr>" unless overtime == 0.0
end
total, overtime = employee_total
output+="<tr><td><h4>#{self.name.to_s} Net Time</h4></td><td style='background-color:#9F9'><h3><b><u>#{total.round_to(2)} hrs.</u></b></h3></td></tr>"
output+="<tr><td><h4>#{self.name.to_s} Net Overtime</h4></td><td style='background-color:#F99'><h3><b><u>#{overtime.round_to(2)} hrs.</u></b></h3></td></tr>" unless overtime == 0.0
#output+="<tr><td><h4>@ $#{@@payrate[self.name]}/hr</h4></td><td><h4><b>$%.2f</b></h4></td></tr>" % (@@payrate[self.name] * total) unless @@payrate[self.name] == nil
output+="</table>"
output
end
end
def clean_time(t)
if t.index(':') == nil
if t.length <= 2 #time with no minutes. ie: 10, 8, 3
t = t.to_s + ':00'
elsif t.length >= 3 #time with no : character. ie: 1013, 805, 304
t = t.insert(-3, ':') #1003 => 10:03
end
end
t
end
#read timecard file
def extract_data(content)
employees = []
lines = content.split(/\r?\n/)
while(name = lines.shift)
e = Employee.new(name.chomp)
week = 0
# print "Processing #{e.name}..."
while(line=lines.shift )
next if line.index('#')
break if(line.chomp=='')
if line.index('week')
week += 1
# print "processing #{e.name}'s week ##{week+1}..."
# line = lines.shift
next
end
begin
line=line.split(/[\s\.+-]/) #\s = space, \. = period. [\s\.+-] = space, period, -, or +
break if(line.size % 2 == 1)
d = Day.new
line.each_with_index{|t,i| line[i] = clean_time(t)} #correct for single-digit times. ie: 10, 3, 8
d<<[line[0],line[1]] #add to the day the first timepair
d<<[line[2],line[3]] unless line.size < 3 #add to the day the second timepair (unless there isn't a second timepair)
e.<<(d, week) #add the day to the employee at the correct week
rescue
if require 'pry'
binding.pry
end
end
end
employees << e
# puts
end
employees
end
# puts Hook['params']
content = if defined? Hook
Hook['params']["file"]["_readableState"]["buffer"].map{|b| b["data"]}.flatten.pack("c*")
else
ARGF.read
end
# puts content
employees = extract_data(content)
# p employees
#Write File
title = "{{title}}"
result = ""
result<<("<html>\n\t<head>\n\t\t<title>#{title}</title>\n\t</head>\n\t<body>\n\t\t<center>\n<h1>#{title}</h1><table cellpadding='5px'><tr valign='top' height='1000px'>")
employees.each_with_index{|e,i|
result<< "<td>" + e.to_html + "</td>"
result<< "\n</tr>\n<tr valign='top' height='1050px'>" if (i+1)%4==0 && employees[i+1] != nil
}
result<<("\n</tr></table>\t\t</center>\n\t</body>\n</html>")
puts result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment