|
16 | 16 |
|
17 | 17 | # default output CSV columns for Harvest |
18 | 18 | HARVEST_COLUMNS = ["Date", "Client", "Project", "Task", "Notes", "Hours", "First name", "Last name"] |
| 19 | +# default output CSV columns for Justworks |
| 20 | +JUSTWORKS_COLUMNS = ["First Name", "Last Name", "Work Email", "Start Date", "End Date", "Regular Hours"] |
19 | 21 |
|
20 | 22 |
|
21 | 23 | @cache |
@@ -121,6 +123,52 @@ def convert_to_harvest( |
121 | 123 | files.write_csv(output_path, source, columns=output_cols) |
122 | 124 |
|
123 | 125 |
|
| 126 | +def convert_to_justworks( |
| 127 | + source_path: str | TextIO = sys.stdin, |
| 128 | + output_path: str | TextIO = sys.stdout, |
| 129 | + output_cols: list[str] = JUSTWORKS_COLUMNS, |
| 130 | + **kwargs, |
| 131 | +): |
| 132 | + """Convert Toggl formatted entries in source_path to equivalent Justworks formatted entries. |
| 133 | +
|
| 134 | + Args: |
| 135 | + source_path: The path to a readable CSV file of Toggl time entries; or a readable buffer of the same. |
| 136 | +
|
| 137 | + output_path: The path to a CSV file where Harvest time entries will be written; or a writeable buffer for the same. |
| 138 | +
|
| 139 | + output_cols (list[str]): A list of column names for the output |
| 140 | +
|
| 141 | + Returns: |
| 142 | + None. Either prints the resulting CSV data or writes to output_path. |
| 143 | + """ |
| 144 | + source = _prepare_input( |
| 145 | + source_path=source_path, |
| 146 | + column_renames={ |
| 147 | + "Email": "Work Email", |
| 148 | + "First name": "First Name", |
| 149 | + "Hours": "Regular Hours", |
| 150 | + "Last name": "Last Name", |
| 151 | + "Start date": "Start Date", |
| 152 | + }, |
| 153 | + ) |
| 154 | + |
| 155 | + # aggregate hours per person per day |
| 156 | + cols = ["Work Email", "First Name", "Last Name", "Start Date"] |
| 157 | + people = source.sort_values(cols).groupby(cols, observed=False) |
| 158 | + people_agg = people.agg({"Regular Hours": "sum"}) |
| 159 | + people_agg.reset_index(inplace=True) |
| 160 | + |
| 161 | + # aggregate hours per person and rollup to the week (starting on Sunday) |
| 162 | + cols = ["Work Email", "First Name", "Last Name"] |
| 163 | + weekly_agg = people_agg.groupby(cols).resample("W", label="left", on="Start Date") |
| 164 | + weekly_agg = weekly_agg["Regular Hours"].sum().reset_index() |
| 165 | + |
| 166 | + # calculate the week end date (the following Saturday) |
| 167 | + weekly_agg["End Date"] = weekly_agg["Start Date"] + pd.Timedelta(days=6) |
| 168 | + |
| 169 | + files.write_csv(output_path, weekly_agg, columns=output_cols) |
| 170 | + |
| 171 | + |
124 | 172 | def download_time_entries( |
125 | 173 | start_date: datetime, |
126 | 174 | end_date: datetime, |
|
0 commit comments