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.
Files changed (28) hide show
  1. {papi_projects-0.4.0 → papi_projects-0.4.1}/PKG-INFO +2 -1
  2. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/wrappers.py +0 -2
  3. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/PKG-INFO +2 -1
  4. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/requires.txt +1 -0
  5. {papi_projects-0.4.0 → papi_projects-0.4.1}/pyproject.toml +2 -1
  6. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/generate_timesheet.py +80 -19
  7. {papi_projects-0.4.0 → papi_projects-0.4.1}/README.md +0 -0
  8. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/__init__.py +0 -0
  9. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/project.py +0 -0
  10. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/task.py +0 -0
  11. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/user.py +0 -0
  12. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi/workorder.py +0 -0
  13. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/SOURCES.txt +0 -0
  14. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/dependency_links.txt +0 -0
  15. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/entry_points.txt +0 -0
  16. {papi_projects-0.4.0 → papi_projects-0.4.1}/papi_projects.egg-info/top_level.txt +0 -0
  17. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/__init__.py +0 -0
  18. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/collate_toggl_hours.py +0 -0
  19. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_notion_project.py +0 -0
  20. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_notion_task.py +0 -0
  21. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_project.py +0 -0
  22. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/create_toggl_project.py +0 -0
  23. {papi_projects-0.4.0 → papi_projects-0.4.1}/scripts/test_notion.py +0 -0
  24. {papi_projects-0.4.0 → papi_projects-0.4.1}/setup.cfg +0 -0
  25. {papi_projects-0.4.0 → papi_projects-0.4.1}/tests/test_project.py +0 -0
  26. {papi_projects-0.4.0 → papi_projects-0.4.1}/tests/test_task.py +0 -0
  27. {papi_projects-0.4.0 → papi_projects-0.4.1}/tests/test_user.py +0 -0
  28. {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.0
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.0
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
 
@@ -3,3 +3,4 @@ httpx>=0.27.2
3
3
  tinydb>=4.8.0
4
4
  python-dotenv>=1.0.0
5
5
  pyperclip>=1.9.0
6
+ pandas>=2.3.3
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "papi-projects"
3
- version = "0.4.0"
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, omit to write to stdout",
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(notion_projects_db, project_id, workorders_db_id=notion_workorders_db)
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(workorders_db_id=notion_workorders_db, workorder_id=workorder_id)
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
- hours = float(hours_dict[project_id])
118
- print(
119
- f"{workorder.id}\t"
120
- f"{project_id}\t"
121
- f"{workorder.payment_type}\t"
122
- f"{workorder.costing_rate}\t"
123
- f"{workorder.hourly_rate}\t"
124
- f"{hours}\t"
125
- f"{calculate_cost(hours, workorder.hourly_rate)}\t"
126
- f"{project.name}\t"
127
- f"{project.id}: {project.name}"
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
- warnings.warn("Start time must not be more than 3 months ago!")
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