Quick and dirty CLI script to give an overview of one's worked hours on Click-Up by project between two dates.
This comes in handy for invoicing your customer.
Requests to the Click-Up REST V2 API are made for you using your Click-Up team_id
(optional) and Click-Up pk_*
API key (called token here).
Possible outputs are: JSON, HTML, PDF, with optional company logo, interval dates, customer name, consultant name.
This Python 3.x project leverages:
- WeasyPrint for PDF rendering,
- the Click-Up REST API to get time tracking info using your API token,
- Jinja2 for HTML-templating,
- Babel/gettext for translation,
- Fire for entry point conversion into a CLI application.
The command works with a compulsory --click-up-token
parameter and optional --click-up-team-id
parameter, which you can provide as CLICKUP_PK
and CLICKUP_TEAM_ID
environment variables (or within a .env
file, mimicking provided .env.tpl
).
If the team ID (a digits value) is absent, it will be guessed from the user's teams as returned by the related Click-Up API endpoint. If that user has several teams, those are printed before exiting.
pip install -r requirements.txt
python click_up_timesheeting.py --click-up-token='pk_MY API KEY' [--click-up-team-id='MY_DIGITS_TEAMID']
See the --help
or examples/quickstart sections below for more information.
python click_up_timesheeting.py --help
See the examples/
directory for sample JSON, HTML and PDF files using the template and company logo from the templates/
directory.
A little preview:
-
Optionally add your Click-Up private key to
.env
(a copy of.env.tpl
) -
Below step creates and enables a virtual environment if you have none yet:
python -m venv venv; . venv/bin/activate
-
Install dependencies (at best in a Python virtual environment):
pip install -r requirements.txt
-
Run with optional date boundaries parameters and Click-Up token:
python click_up_timesheeting.py # from now since 1 year ago
Output:
Gathering Click-Up time entries from 2021-12-06 18:20:16 to 2022-12-06 18:20:16 ................................................................................................................................... Daily time sheet: Tue, 01 Nov 2022 2h36m55 Wed, 02 Nov 2022 2h13m0 Thu, 03 Nov 2022 3h11m0 Tasks summary: Task 1 Project B Listing C 2h36m55 Task 2 Project C Listing C 5h24m0 .... Total: 8h0m55
python click_up_timesheeting.py --from_date=2022-11-01 # till now
python click_up_timesheeting.py --to_date=2022-12-30 # from 1 year before that date (default shift)
python click_up_timesheeting.py --from_date=2022-11-01 --to_date=2022-11-30 # with times from 00:00:00 to 23:59:59
python click_up_timesheeting.py --from_date=2022-11-01 --to_date=2022-11-30 --click_up_token=pk_SOMETHING --click_up_team_id=123DIGITSONLY45 # with Click-Up API token and team_id provided on CLI instead of .env
The JSON file which the script outputs can be piped again to by command to prevent fetching Click-Up again:
python click_up_timesheeting.py --from-date=2023-01-01 --to-date=2023-01-31 --as-json --json-output-path=a.json
python click_up_timesheeting.py --from-date=2023-01-01 --to-date=2023-01-31 --from-json --json-input-path=a.json
The report's template can be fine-tuned in templates/simple-report.html.j2
, using the Jinja2 syntax (similar to Twig in the PHP world).
Internally, the script creates a big Python dictionary, which it can dump as JSON, and/or feeds it to an HTML template to output both the HTML and PDF reports. So that JSON file is useful if you would like to template things your own way.
Use --as-json
and --json-output-path=<full path to a json file>
together.
python click\_up\_timesheeting.py --from-date=2023-01-01 --to-date=2023-01-31 --as-json --json-output-path=a.json
Use --as-html
and --html-output-path=<full path to an HTML file>
together.
python click\_up\_timesheeting.py --from-date=2023-01-01 --to-date=2023-01-31 --as-html --html-output-path=a.html
Use --as-pdf
and --pdf-output-path=<full path to a PDF file>
together.
python click\_up\_timesheeting.py --from-date=2023-01-01 --to-date=2023-01-31 --as-pdf --pdf-output-path=a.pdf
For now english (default) and french are supported, with the --language
option.
python click\_up\_timesheeting.py --from-date=2023-01-01 --to-date=2023-01-31 --as-pdf --pdf-output-path=a.pdf --language=french # or --language=english
The following fields are optional and apply for both HTML & PDF outputs.
Add --output-title="My time record title"
to custome the HTML page title or PDF document title.
Add --company-logo-img-path=<path to your non-SVG raster file>
, successfully tested with PNG. For rendering, the image is encoded to base64 first then injected into the template.
Add --customer-name=<name of customer company or person>
.
Add --consultant-name=<name of consultant>
.
Add --customer-signature-field
to show a customer signature field at the page's bottom.
Add --consultant-signature-field
to show a consultant signature field at the page's bottom.
Translations .po
files in locale/
were created by hand and compiled to .mo
with the following command:
pybabel compile --domain=messages --directory=locale --use-fuzzy
You need to install pytest
, pytest-cov
, requests-mock
and python-slugify
first using a test-oriented requirements file:
pip install -r test-requirements.txt
pip install -r requirements.txt
make tests
Both artifacts/
and artifacts-cli/
directories get created in pytest's current working directory, for generating sample JSON/PDF/HTML files.
An html-cov/
directory containing HTML files is generated by the pytest-cov
for coverage reporting. It also belongs in Github Actions' artifacts.
Head over to the Actions tab to understand how those tests work.
Public domain.