From c5364a27a6e037b81d2417dae01366ff62eda589 Mon Sep 17 00:00:00 2001 From: lcfd <9001053+fedriz@users.noreply.github.com> Date: Sun, 29 Oct 2023 02:13:43 +0200 Subject: [PATCH] Reports for all projects (trak report all) --- cli/trakcli/main.py | 38 +------ cli/trakcli/report/__init__.py | 0 cli/trakcli/report/commands.py | 198 +++++++++++++++++++++++++++++++++ 3 files changed, 200 insertions(+), 36 deletions(-) create mode 100644 cli/trakcli/report/__init__.py create mode 100644 cli/trakcli/report/commands.py diff --git a/cli/trakcli/main.py b/cli/trakcli/main.py index 01afca4..deb3953 100644 --- a/cli/trakcli/main.py +++ b/cli/trakcli/main.py @@ -26,6 +26,7 @@ ) from trakcli.database.models import Record from trakcli.dev.commands import app as dev_app +from trakcli.report.commands import app as report_app from trakcli.initialize import initialize_trak from trakcli.utils.print_with_padding import print_with_padding @@ -44,6 +45,7 @@ ) app.add_typer(config_app, name="config", help="Interact with your configuration.") app.add_typer(projects_app, name="projects", help="Interact with your projects.") +app.add_typer(report_app, name="report", help="See reports for your projects.") @app.callback() @@ -257,39 +259,3 @@ def status( ), ) ) - - -@app.command() -def report( - project: str, - when: Annotated[ - str, - typer.Option( - "--when", - "-w", - help="Look for records in a specific date or range by keyword. \ -Values may be: \ -- today \ -- yesterday \ -- month: the current month \ -- yyyy-mm-dd: like 2023-10-08", - ), - ] = "", - category: Annotated[str, typer.Option("--category", "-c")] = "", - tag: Annotated[str, typer.Option("--tag", "-t")] = "", - billable: Annotated[ - bool, - typer.Option( - "--billable", - "-b", - help="Consider only the billable records.", - ), - ] = False, -): - """ - Report stats for projects. - """ - - get_record_collection( - project=project, billable=billable, category=category, tag=tag, when=when - ) diff --git a/cli/trakcli/report/__init__.py b/cli/trakcli/report/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cli/trakcli/report/commands.py b/cli/trakcli/report/commands.py new file mode 100644 index 0000000..379f17a --- /dev/null +++ b/cli/trakcli/report/commands.py @@ -0,0 +1,198 @@ +# import json +# from rich.panel import Panel +# from rich.table import Table +from datetime import datetime, timedelta +import json +from typing import Annotated +from rich.panel import Panel + +import typer +from trakcli.config.main import get_db_file_path + +from trakcli.database.database import get_record_collection + +from rich import print as rprint + +from trakcli.utils.print_with_padding import print_with_padding +from trakcli.utils.same_week import same_week + +# from trakcli.config.main import CONFIG_FILE_PATH, get_config, get_db_file_path +# from trakcli.config.models import Project +# from trakcli.utils.print_with_padding import print_with_padding +# +# from trakcli.projects.database import ( +# get_projects_from_config, +# get_projects_from_db, +# ) + +app = typer.Typer() + + +@app.command() +def all( + billable: Annotated[ + bool, + typer.Option( + "--billable", + "-b", + help="Consider only the billable records.", + ), + ] = False, + when: Annotated[ + str, + typer.Option( + "--when", + "-w", + help="Look for records in a specific date or range by keyword. \ +Values may be: \ +- today \ +- yesterday \ +- month: the current month \ +- yyyy-mm-dd: like 2023-10-08", + ), + ] = "", +): + """ + Report stats for all projects. + """ + + db_path = get_db_file_path() + + with open(db_path, "r") as db: + db_content = db.read() + + parsed_json = json.loads(db_content) + + grouped = {} + + for record in parsed_json: + project = record.get("project", False) + if project: + del record["project"] + if isinstance(grouped.get(project, False), list): + grouped[project].append(record) + else: + grouped[project] = [record] + + for g in grouped: + records = grouped[g] + + if billable: + records = [ + record for record in grouped[g] if record["billable"] == billable + ] + + if when: + if when == "yesterday": + records = [ + record + for record in records + if datetime.fromisoformat(record["end"]).date() + == datetime.today().date() - timedelta(1) + ] + elif when == "today": + records = [ + record + for record in records + if datetime.fromisoformat(record["end"]).date() + == datetime.today().date() + ] + elif when == "week": + records = [ + record + for record in records + if same_week( + datetime.fromisoformat(record["end"]).date().strftime("%Y%m%d"), + ) + ] + elif when == "month": + + def trunc_datetime(someDate): + return someDate.replace( + day=1, hour=0, minute=0, second=0, microsecond=0 + ) + + records = [ + record + for record in records + if trunc_datetime(datetime.today()) + == trunc_datetime(datetime.fromisoformat(record["end"])) + ] + else: + try: + records = [ + record + for record in records + if datetime.fromisoformat(record["end"]).date() + == datetime.fromisoformat(when).date() + ] + except Exception: + rprint( + Panel( + title="🔴 Invalid date", + renderable=print_with_padding( + """The provided date it's invalid. + + Try with a date like 2023-10-08, or the strings today, yesterday.""" + ), + ) + ) + + acc_seconds = 0 + + for record in records: + start_datetime = datetime.fromisoformat(record["start"]) + end_datetime = datetime.fromisoformat(record["end"]) + + diff = end_datetime - start_datetime + + acc_seconds = acc_seconds + diff.seconds + + m, _ = divmod(diff.seconds, 60) + h, m = divmod(m, 60) + + m, _ = divmod(acc_seconds, 60) + h, m = divmod(m, 60) + + sum_panel = Panel( + print_with_padding(f"[bold]{h}h {m}m[/bold]"), + title=f"🧮 Total spent time on {g}", + ) + + rprint(sum_panel) + + +@app.command() +def single( + project: str, + when: Annotated[ + str, + typer.Option( + "--when", + "-w", + help="Look for records in a specific date or range by keyword. \ +Values may be: \ +- today \ +- yesterday \ +- month: the current month \ +- yyyy-mm-dd: like 2023-10-08", + ), + ] = "", + category: Annotated[str, typer.Option("--category", "-c")] = "", + tag: Annotated[str, typer.Option("--tag", "-t")] = "", + billable: Annotated[ + bool, + typer.Option( + "--billable", + "-b", + help="Consider only the billable records.", + ), + ] = False, +): + """ + Report stats for single projects. + """ + + get_record_collection( + project=project, billable=billable, category=category, tag=tag, when=when + )