Permalink
Show file tree
Hide file tree
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
4 changed files
with
253 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
import csv | ||
import datetime as dt | ||
from decimal import * | ||
import math | ||
|
||
""" | ||
Please write you name here: Salah Abdo | ||
""" | ||
|
||
|
||
def process_shifts(path_to_csv): | ||
with open('work_shifts.csv') as file: | ||
next(file, None) #skip the first line(Header) | ||
reader = csv.reader(file, delimiter=',') | ||
|
||
shifts = {} | ||
|
||
for row in reader: | ||
|
||
startShift = row[3] | ||
endShift = row[1] | ||
|
||
breakNotes = row[0] | ||
|
||
payRate = row[2] | ||
|
||
start_dt = dt.datetime.strptime(startShift, '%H:%M') # convert start time string to time using 24 hour format | ||
end_dt = dt.datetime.strptime(endShift, '%H:%M') | ||
|
||
diff = (end_dt - start_dt) | ||
shiftHours = int((diff.seconds/60)) # convert hour to minutes | ||
|
||
breakTime = breakNotes.split("-") #split each time a - is seen to separate the time | ||
|
||
breakTime0 = breakTime[0].strip() # remove all whitespaces | ||
breakTime1 = breakTime[1].strip() | ||
|
||
if not breakTime0.isdigit() & breakTime1.isdigit(): | ||
if breakTime0[-2:] == "AM": # check if letters AM is present | ||
breakTime0 = breakTime0.replace("AM", "") #remove the letters AM and leave the number as it is | ||
|
||
elif breakTime0[-2:] == "PM": # check if letters PM is present | ||
breakTime0 = breakTime0.replace("PM", "") #remove the letters PM | ||
breakTime0 = float(breakTime0) + 12 # convert number to 24 hour time | ||
|
||
elif breakTime0.isdigit(): # for instances where the break start time and end time using different format ("4-4:10PM") | ||
if breakTime1[-2:] == "AM": | ||
breakTime0 = float(breakTime0) | ||
else: | ||
breakTime0 = float(breakTime0) +12 | ||
|
||
if breakTime1[-2:] == "AM": | ||
breakTime1 = breakTime1.replace("AM", "") | ||
|
||
elif breakTime1 [-2:] == "PM": | ||
breakTime1 = breakTime1.replace("PM", "") | ||
breakTime1 = float(breakTime1) + 12 | ||
|
||
elif breakTime1.isdigit(): | ||
if breakTime0[-2:] == "AM": | ||
breakTime1 = float(breakTime0) | ||
elif breakTime1.isdigit() & breakTime0[-2:] == "PM": | ||
breakTime1 = float(breakTime0) +12 | ||
|
||
|
||
|
||
endBreak = str(round(Decimal(breakTime1),2)) #convert to decimal, rounded up to two decimal places to represent time | ||
endBreak = endBreak.replace(".", ":") | ||
endBreak = dt.datetime.strptime(endBreak, '%H:%M') | ||
|
||
startBreak = str(round(Decimal(breakTime0),2)) | ||
startBreak = startBreak.replace(".", ":") | ||
startBreak = dt.datetime.strptime(startBreak, '%H:%M') | ||
|
||
breakTime = (endBreak - startBreak) | ||
breakHours = int((breakTime.seconds/60)) #calculate total break in minutes | ||
|
||
hoursWorked = shiftHours - breakHours | ||
|
||
labourCost = int((hoursWorked/60) * float(payRate)) | ||
|
||
if startShift in shifts: # if start time is already present then increase the labour cost for that specific time | ||
shifts[startShift] += labourCost | ||
else: | ||
shifts[startShift] = labourCost | ||
|
||
return(shifts) | ||
|
||
def process_sales(path_to_csv): | ||
|
||
with open('transactions.csv') as file: | ||
next(file, None) #skip the first line(Header) | ||
reader = csv.reader(file, delimiter=',') | ||
|
||
sales = {} | ||
|
||
for row in reader: | ||
sale = float(row[0]) | ||
time = row[1][:2] + ':00' # time rounded up to every hour | ||
|
||
if time in sales: | ||
sales[time] += int(sale) | ||
else: | ||
sales[time] = int(sale) | ||
|
||
|
||
return(sales) | ||
|
||
def compute_percentage(shifts, sales): | ||
|
||
computePercentage = {} | ||
|
||
for time in sorted(shifts): # iterate over key only | ||
labourCost = shifts[time] | ||
try: | ||
sale = sales[time] | ||
percentage = round((labourCost / sale)*100,2) | ||
except: | ||
sale = None | ||
percentage = labourCost * (-1) | ||
computePercentage[time] = percentage | ||
return(computePercentage) | ||
|
||
|
||
def best_and_worst_hour(percentages): | ||
|
||
bestAndWorst = [] | ||
|
||
worstHour = min(percentages, key=percentages.get) # gets smallest value key in the dictionary | ||
|
||
for key, value in percentages.items(): | ||
bestHourSales = math.inf #set to infinity | ||
bestHour = "" | ||
if value > 0: | ||
if value < bestHourSales: | ||
bestHourSales = value | ||
bestHour = key | ||
|
||
bestAndWorst.append(bestHour) | ||
bestAndWorst.append(worstHour) | ||
|
||
return(bestAndWorst) | ||
|
||
def main(path_to_shifts, path_to_sales): | ||
""" | ||
Do not touch this function, but you can look at it, to have an idea of | ||
how your data should interact with each other | ||
""" | ||
|
||
shifts_processed = process_shifts(path_to_shifts) | ||
sales_processed = process_sales(path_to_sales) | ||
percentages = compute_percentage(shifts_processed, sales_processed) | ||
best_hour, worst_hour = best_and_worst_hour(percentages) | ||
return best_hour, worst_hour | ||
|
||
if __name__ == '__main__': | ||
# You can change this to test your code, it will not be used | ||
path_to_sales = "transactions.csv" | ||
path_to_shifts = "work_shifts.csv" | ||
best_hour, worst_hour = main(path_to_shifts, path_to_sales) | ||
|
||
|
||
# Please write you name here: Salah Abdo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
===Tenzo Coding Challenge=== | ||
|
||
Congratulations on making it to the first part of the Tenzo Interview process | ||
|
||
NOTE: This exercise is in Python 3 -- if you wish to change to a language of | ||
your choice, that is completely fine. | ||
|
||
We want to understand the most and least profitable hour of the day for a given restaurant when looking at labour cost. | ||
|
||
You'll have two csvs, one describing the shifts, and one describing the hourly | ||
sales. | ||
|
||
|
||
==LABOUR DATA== | ||
A shift will include the pay-rate (per hour), the start and end time, and a text | ||
field where the manager will enter break info. This may vary depending on the individual manager. | ||
|
||
For example: | ||
|
||
{ | ||
'break_notes': '15-18', | ||
'start_time': '10:00', | ||
'end_time': '23:00', | ||
'pay_rate': 10.0 | ||
} | ||
|
||
The data given shows a shift started at 10AM and ended at 11PM. However, the break_notes "15-18" indicates that the staff member took a 3 hour break in the middle of the day (when they would not be paid). The employee was paid £10 per hour. | ||
|
||
|
||
==SALES DATA== | ||
This shows you a set of transactions: | ||
|
||
For example | ||
|
||
[ | ||
{ | ||
'time' : '10:31, | ||
'amount' : 50.32 | ||
} | ||
] | ||
We are hoping that you can compute different metrics for the different hours, | ||
such as the total sales during this hour, the cost of labour for this hour, and | ||
the cost of labour as percentage of sales. | ||
|
||
e.g., | ||
|
||
Hour Sales Labour % | ||
7:00 100 30 30% | ||
8:00 300 60 20% | ||
Lastly, we are hoping that you can output which hour was the best and worst in terms of labour cost as a percentage of sales. | ||
|
||
The empty Solution.py file contains some function, where the output is well | ||
defined. This will be used for our tests, so be sure to output right answers | ||
(it is not that hard to compute the result by hand, and compare it to the | ||
output of your program) in the right format. If you need to create other | ||
functions, you're free to do so, just keep in mind that the functions that are | ||
already defined need to work. Also , for the sake of testing, do not print any alert messages or anything to stdout. | ||
|
||
Please write your name at the top and the bottom of your solution. | ||
|
||
When you are done, please send your python file and your CV in separate file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
amount,time | ||
100.32,10:31 | ||
30.56,10:56 | ||
300.65,11:05 | ||
20.0,11:31 | ||
54.56,12:36 | ||
220.09,12:45 | ||
240.0,12:59 | ||
270.43,13:10 | ||
135.65,13:15 | ||
15.43,14:04 | ||
162.34,14:06 | ||
63.43,15:04 | ||
75.42,16:31 | ||
142.34,17:31 | ||
57.54,18:31 | ||
450.54,18:31 | ||
240.54,18:56 | ||
240.54,19:15 | ||
180.54,19:45 | ||
240.54,21:45 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
break_notes,end_time,pay_rate,start_time | ||
15-18,23:00,10.0,10:00 | ||
18.30-19.00,23:00,12.0,18:00 | ||
4PM-5PM,22:30,14.0,12:00 | ||
3-4,18:00,10.0,09:00 | ||
4-4.10PM,23:00,20.0,09:00 | ||
15 - 17,23:00,10.0,11:00 | ||
11 - 13,16:00,10.0,10:00 |