From d3ca7c01968948ac10897d6fe2bcd1a9296429c3 Mon Sep 17 00:00:00 2001 From: San Jacobs Date: Thu, 30 Dec 2021 07:07:18 +0100 Subject: Basic functionality completed --- satscalc.py | 204 ++++++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 150 insertions(+), 54 deletions(-) diff --git a/satscalc.py b/satscalc.py index c05d232..8ccf8d7 100755 --- a/satscalc.py +++ b/satscalc.py @@ -1,13 +1,6 @@ #!usr/bin/env python3 -import datetime -class workday: - def __init__(self, calltime, wraptime, ot_warned=True, warned_until=wraptime): - self.call = calltime - self.wrap = wraptime - self.otw = ot_warned - self.ott = warned_until - +import datetime def timeInput(prompt, fulldate=False): @@ -32,64 +25,167 @@ def timeInput(prompt, fulldate=False): return t + +def hours_between(time1, time2): + """Returns the difference beween two times.""" + if time2 > time1: + return (time2 - time1).total_seconds()/3600 + return (time1 - time2).total_seconds()/3600 + + +def calc_overtime_factor(hours, warned): + """Loops through and sums together hour-pay-factor for every hour of overtime""" + output = 0 + hours_passed = 1 + + if warned: + time_and_half_length = 3 + else: + time_and_half_length = 1 + + while hours > 0: + if hours_passed <= time_and_half_length: + # 50% extra for the first 3 hours of warned overtime, first 1 hour of unwarned. + output += 1.5 * min(1, hours) + elif hours_passed <= 7: + # 100% extra for all overtime beyond 3 hours. + output += 2 * min(1, hours) + else: + # 200% extra for all overtime beyond 7 hours. + # FIXME: The actual rule is 200% extra for anything beyond a 14-hour day, but since there is no support for pre-call work yet, this is fine. For now. + output += 3 * min(1, hours) + hours -= 1 + hours_passed += 1 + + return output + + def floatify(hour, minutes): # Turns hour and minute into a single float that is easier to do math with return float(hour+(minutes/60.0)) -baserate = int(input("What's your base dayrate (sats)? ")) -hourly_rate = baserate/7.5 -print("Hourly rate:", str(hourly_rate)) -print("\nTime to add your hours of work.") -# --- Data gathering loop --- - -while True: - calltime = timeInput("CALL TIME (24-hour format. Leave blank to continue.)", True) - if calltime == "": - break - wraptime = timeInput("\nWRAP TIME (24-hour format)") - - # Giving wrap same date as call - wraptime = wraptime.replace(year=calltime.year, month=calltime.month, day=calltime.day) - # If clock nr at wrap is equal to or lower than call, then a day has passed. - if floatify(wraptime.hour, wraptime.minute) <= floatify(calltime.hour, calltime.minute): - wraptime += datetime.timedelta(days=1) +if __name__ == "__main__": - difference = wraptime-calltime - hours_worked = difference.total_seconds()/3600 - - print("\nCalltime:",calltime) - print("Wraptime:",wraptime) - print("Delta:",hours_worked,"hours.\n") + baserate = int(input("What's your base dayrate (sats)? ")) + hourly_rate = baserate/7.5 - # This part makes no sense. Don't worry. It'll be made to make sense. + print("Hourly rate:", str(hourly_rate)) - overtime = hours_worked > 8 - if overtime: - overtime_hours = hours_worked-8 - print("Overtime detected.") - warned_overtime = "y" in input("Was this overtime warned about before 12 o'clock the day before? [y/n]: ").lower() - if warned_overtime: - if "n" in input("Was it warned of entirely? [y/n] ").lower(): - #overtime_warned_until = timeInput("Until what time was it warned?") - print("Feature not yet implemented.") + social_costs = not "n" in input("Add 26% social costs? [y/n] ").lower() + + print("\nTime to add your hours of work.") + +# --- Data gathering loop --- + + workdays = [] + + while True: + calltime = timeInput("CALL TIME (24-hour format. Leave blank to continue.)", True) + if calltime == "": + break + wraptime = timeInput("\nWRAP TIME (24-hour format)") - -# --- Price calculation --- + # Giving wrap same date as call + wraptime = wraptime.replace(year=calltime.year, month=calltime.month, day=calltime.day) + # If clock nr at wrap is equal to or lower than call, then a day has passed. + if floatify(wraptime.hour, wraptime.minute) <= floatify(calltime.hour, calltime.minute): + wraptime += datetime.timedelta(days=1) + + difference = wraptime-calltime + hours_worked = difference.total_seconds()/3600 + + print("\nCalltime:",calltime) + print(f"Wraptime:",wraptime) + print(f"Delta: {hours_worked} hours.\n") -# NOTE: -# First two hours of warned overtime are 50%, unwarned is 100% -# Any work after 20:00 is overtime -# There is a rule that you always have to invoice for 4 hours or more pr day on ad-shoots. Take this into account. -# + # This part makes no sense. Don't worry. It'll be made to make sense. + + overtime = hours_worked > 8 + if overtime: + overtime_hours = hours_worked-8 + print("Overtime detected.") + warned_overtime = "y" in input("Was this overtime warned about before 12 o'clock the day before? [y/n]: ").lower() + if warned_overtime: + if "n" in input("Was it warned of entirely? [y/n] ").lower(): + #overtime_warned_until = timeInput("Until what time was it warned?") + print("Feature not yet implemented.") + workdays.append({ + "call": calltime, + "wrap": wraptime, + "otw": warned_overtime, + "ot": overtime, + }) + else: + workdays.append({ + "call": calltime, + "wrap": wraptime, + }) + + + + # --- Price calculation --- -# Extremely naive calculation -sum = 0 -if overtime: - sum += overtime_hours*(hourly_rate*1.5) + # NOTE: + # First two hours of warned overtime are 50%, unwarned is 100% + # Any work after 20:00 is overtime + # There is a rule that you always have to invoice for 4 hours or more pr day on ad-shoots. Take this into account. + # If you get warned about some overtime, but they go beyond that, anything beyond that should be treated as thouogh it was unwarned. + # This means I'll have to ask for the specific time things were supposed to be done. + + # TODO: Doesn't take weekends into account yet + for day_index, each_day in enumerate(workdays): + + if day_index > 0: + previous_day = workdays[day_index-1] + # TODO: Possibly just put the stuff about 10 hours minimum between workdays here. That's a 200% bonus. + else: + previous_day = 0 + + worktime = hours_between(each_day["call"], each_day["wrap"]) + each_day["hours"] = worktime + + if worktime == 8: + each_day["category"] = "Normal day" + each_day["price"] = baserate + elif worktime > 8: + each_day["category"] = "Overtime" + overtime = worktime-8 + ot_factor = calc_overtime_factor(overtime, each_day["otw"]) + each_day["price"] = baserate + (hourly_rate*ot_factor) + elif 4 < worktime < 8: + each_day["category"] = "Short day" + overtime = worktime-8 + each_day["price"] = hourly_rate*worktime + elif worktime <= 4: + each_day["category"] = "Sub 4-hour day" + each_day["price"] = hourly_rate*4 + else: + print("This shouldn't be possible, something is very wrong.") + quit() + + -print("\nDifference:", difference) -print("Hours worked:", hours_worked) + # --- Printing receipt --- + + total = 0 + + print("\n\nCalculation via satscalc by SanJacobs.") + print("Please note point 15 (Disclaimer of Warranty) of the GPLv3.") + for day_index, each_day in enumerate(workdays): + print("\n---") + print(f"Day #{day_index+1}: {each_day['call'].date()} - {each_day['category']}\n") + + print("Calltime: " + str(each_day["call"].time())) + print("Finished at: " + str(each_day["wrap"].time())) + if "ot" in each_day: + print("Overtime: " + each_day["ot"] + " hour(s)") + print("Warned? " + each_day["otw"]) + print("Price: " + each_day["price"]) + total += each_day["price"] + + print("\n\n-----") + print("TOTAL:", total) -- cgit v1.2.1