papi-projects 0.4.0__tar.gz → 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {papi_projects-0.4.0 → papi_projects-0.4.1}/PKG-INFO +2 -1
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/wrappers.py +0 -2
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/PKG-INFO +2 -1
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/requires.txt +1 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/pyproject.toml +2 -1
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/generate_timesheet.py +80 -19
- {papi_projects-0.4.0 → papi_projects-0.4.1}/README.md +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/__init__.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/project.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/task.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/user.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/workorder.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/SOURCES.txt +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/dependency_links.txt +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/entry_points.txt +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/top_level.txt +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/__init__.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/collate_toggl_hours.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_notion_project.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_notion_task.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_project.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_toggl_project.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/test_notion.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/setup.cfg +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/tests/test_project.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/tests/test_task.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/tests/test_user.py +0 -0
- {papi_projects-0.4.0 → papi_projects-0.4.1}/tests/test_wrappers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: papi-projects
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: PAPI is an API for managing projects
|
|
5
5
|
Author-email: sandyjmacdonald <sandyjmacdonald@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -11,6 +11,7 @@ Requires-Dist: httpx>=0.27.2
|
|
|
11
11
|
Requires-Dist: tinydb>=4.8.0
|
|
12
12
|
Requires-Dist: python-dotenv>=1.0.0
|
|
13
13
|
Requires-Dist: pyperclip>=1.9.0
|
|
14
|
+
Requires-Dist: pandas>=2.3.3
|
|
14
15
|
|
|
15
16
|
PAPI is an API for managing projects.
|
|
16
17
|
|
|
@@ -799,7 +799,6 @@ class NotionWrapper(Protocol):
|
|
|
799
799
|
payment_type=payment_type,
|
|
800
800
|
notion_page_id=notion_page_id,
|
|
801
801
|
)
|
|
802
|
-
print(workorder)
|
|
803
802
|
if len(workorders):
|
|
804
803
|
logger.info(f"{len(workorders)} Notion workorders found")
|
|
805
804
|
else:
|
|
@@ -974,7 +973,6 @@ class NotionWrapper(Protocol):
|
|
|
974
973
|
project_owner =[owner["name"] for owner in p["properties"]["Owner"]["people"]]
|
|
975
974
|
project_status = p["properties"]["Status"]["status"]["name"]
|
|
976
975
|
project_priority = p["properties"]["Priority"]["select"]["name"]
|
|
977
|
-
print(p["properties"])
|
|
978
976
|
notion_page_id = p["id"]
|
|
979
977
|
if "TEMPLATE" not in project_name:
|
|
980
978
|
user_id = p["properties"]["PI Code"]["rollup"]["array"][0]["rich_text"][0][
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: papi-projects
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: PAPI is an API for managing projects
|
|
5
5
|
Author-email: sandyjmacdonald <sandyjmacdonald@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -11,6 +11,7 @@ Requires-Dist: httpx>=0.27.2
|
|
|
11
11
|
Requires-Dist: tinydb>=4.8.0
|
|
12
12
|
Requires-Dist: python-dotenv>=1.0.0
|
|
13
13
|
Requires-Dist: pyperclip>=1.9.0
|
|
14
|
+
Requires-Dist: pandas>=2.3.3
|
|
14
15
|
|
|
15
16
|
PAPI is an API for managing projects.
|
|
16
17
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "papi-projects"
|
|
3
|
-
version = "0.4.
|
|
3
|
+
version = "0.4.1"
|
|
4
4
|
description = "PAPI is an API for managing projects"
|
|
5
5
|
authors = [{ name = "sandyjmacdonald", email = "sandyjmacdonald@gmail.com" }]
|
|
6
6
|
license = "MIT"
|
|
@@ -13,6 +13,7 @@ dependencies = [
|
|
|
13
13
|
"tinydb>=4.8.0",
|
|
14
14
|
"python-dotenv>=1.0.0",
|
|
15
15
|
"pyperclip>=1.9.0",
|
|
16
|
+
"pandas>=2.3.3",
|
|
16
17
|
]
|
|
17
18
|
|
|
18
19
|
[project.scripts]
|
|
@@ -2,10 +2,10 @@ import argparse
|
|
|
2
2
|
import pendulum
|
|
3
3
|
import warnings
|
|
4
4
|
from papi.wrappers import TogglTrackWrapper, NotionWrapper
|
|
5
|
-
from papi import config
|
|
5
|
+
from papi import config, setup_logger
|
|
6
6
|
from papi.project import get_project_ids, check_project_id
|
|
7
|
-
|
|
8
7
|
from decimal import Decimal, ROUND_UP
|
|
8
|
+
import pandas as pd
|
|
9
9
|
|
|
10
10
|
def initialise_toggl(toggl_api_key, toggl_workspace):
|
|
11
11
|
"""Initialises the TogglTrackWrapper.
|
|
@@ -65,7 +65,6 @@ def get_toggl_hours(start_time, end_time, toggl):
|
|
|
65
65
|
|
|
66
66
|
def main():
|
|
67
67
|
"""Main function of generate-timesheet script"""
|
|
68
|
-
|
|
69
68
|
# Set up argparse
|
|
70
69
|
parser = argparse.ArgumentParser()
|
|
71
70
|
parser.add_argument(
|
|
@@ -74,15 +73,24 @@ def main():
|
|
|
74
73
|
parser.add_argument(
|
|
75
74
|
"-e", "--end", type=str, help="end date in YYYY-MM-DD format, if none supplied then end date is now", default=False
|
|
76
75
|
)
|
|
76
|
+
parser.add_argument(
|
|
77
|
+
"--disable-logging",
|
|
78
|
+
action="store_true",
|
|
79
|
+
help="disable logging output for the papi library",
|
|
80
|
+
)
|
|
77
81
|
parser.add_argument(
|
|
78
82
|
"-o",
|
|
79
83
|
"--output",
|
|
80
84
|
type=str,
|
|
81
|
-
help="output TSV filename
|
|
85
|
+
help="output TSV filename",
|
|
82
86
|
default=False,
|
|
87
|
+
required=True
|
|
83
88
|
)
|
|
84
89
|
args = parser.parse_args()
|
|
85
90
|
|
|
91
|
+
if not args.disable_logging:
|
|
92
|
+
logger = setup_logger(True, "WARNING", None)
|
|
93
|
+
|
|
86
94
|
# Set up start/end date
|
|
87
95
|
start_date = args.start
|
|
88
96
|
start_time = pendulum.parse(start_date).to_rfc3339_string()
|
|
@@ -105,29 +113,82 @@ def main():
|
|
|
105
113
|
notion_projects_db = config["NOTION_PROJECTS_DB"]
|
|
106
114
|
notion_workorders_db = config["NOTION_WORKORDERS_DB"]
|
|
107
115
|
notion = NotionWrapper(notion_api_secret)
|
|
108
|
-
|
|
109
116
|
project_ids = hours_dict.keys()
|
|
117
|
+
output = args.output
|
|
118
|
+
df = pd.DataFrame(
|
|
119
|
+
columns=[
|
|
120
|
+
"workorder",
|
|
121
|
+
"project_id",
|
|
122
|
+
"payment_type",
|
|
123
|
+
"costing_rate",
|
|
124
|
+
"hourly_rate",
|
|
125
|
+
"hours",
|
|
126
|
+
"cost",
|
|
127
|
+
"description",
|
|
128
|
+
"agresso_description",
|
|
129
|
+
]
|
|
130
|
+
)
|
|
131
|
+
|
|
110
132
|
for project_id in project_ids:
|
|
133
|
+
hours = float(hours_dict[project_id])
|
|
134
|
+
payment_type = ""
|
|
135
|
+
costing_rate = ""
|
|
136
|
+
hourly_rate = ""
|
|
137
|
+
cost = 0.0
|
|
138
|
+
chargeable = False
|
|
139
|
+
workorder_id = ""
|
|
111
140
|
if check_project_id(project_id):
|
|
112
|
-
project = notion.get_project(
|
|
141
|
+
project = notion.get_project(
|
|
142
|
+
notion_projects_db,
|
|
143
|
+
project_id,
|
|
144
|
+
workorders_db_id=notion_workorders_db
|
|
145
|
+
)
|
|
146
|
+
project_name = project.name
|
|
113
147
|
workorder_id = project.workorder
|
|
114
148
|
if workorder_id is not None:
|
|
115
|
-
workorder = notion.get_workorder(
|
|
149
|
+
workorder = notion.get_workorder(
|
|
150
|
+
workorders_db_id=notion_workorders_db,
|
|
151
|
+
workorder_id=workorder_id
|
|
152
|
+
)
|
|
116
153
|
if workorder.is_complete():
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
f"{
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
f"{
|
|
154
|
+
payment_type = workorder.payment_type
|
|
155
|
+
costing_rate = workorder.costing_rate
|
|
156
|
+
hourly_rate = workorder.hourly_rate
|
|
157
|
+
cost = calculate_cost(hours, workorder.hourly_rate)
|
|
158
|
+
chargeable = True
|
|
159
|
+
logger.warning(
|
|
160
|
+
f"Project: {project_id}: Has complete data and is chargeable"
|
|
161
|
+
)
|
|
162
|
+
else:
|
|
163
|
+
logger.warning(
|
|
164
|
+
f"Project {project_id}: Workorder {workorder.id} has incomplete data!"
|
|
128
165
|
)
|
|
166
|
+
else:
|
|
167
|
+
workorder_id = ""
|
|
168
|
+
logger.warning(f"Project {project_id}: Workorder is missing!")
|
|
169
|
+
else:
|
|
170
|
+
logger.warning(f"Project {project_id}: Not a valid project ID!")
|
|
171
|
+
project_name = project_id
|
|
172
|
+
|
|
173
|
+
agresso_description = f"{project_id}: {project_name}"
|
|
174
|
+
description = project_name
|
|
175
|
+
|
|
176
|
+
df.loc[len(df)] = [
|
|
177
|
+
workorder_id,
|
|
178
|
+
project_id,
|
|
179
|
+
payment_type,
|
|
180
|
+
costing_rate,
|
|
181
|
+
hourly_rate,
|
|
182
|
+
hours,
|
|
183
|
+
cost,
|
|
184
|
+
description,
|
|
185
|
+
agresso_description,
|
|
186
|
+
]
|
|
187
|
+
|
|
188
|
+
df.to_csv(output, sep="\t", index=False)
|
|
189
|
+
logger.warning(f"{len(df)} journal entries successfully written to {output}")
|
|
129
190
|
else:
|
|
130
|
-
|
|
191
|
+
logger.warning("Start time must not be more than 3 months ago!")
|
|
131
192
|
|
|
132
193
|
if __name__ == "__main__":
|
|
133
194
|
main()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|