| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355 | 
							- from typing import Optional
 
- import click
 
- from prettytable import PrettyTable
 
- from piket_client.model import (
 
-     AardbeiActivity,
 
-     ServerStatus,
 
-     NetworkError,
 
-     Consumption,
 
-     AardbeiPeopleDiff,
 
-     Person,
 
-     Settlement,
 
-     ConsumptionType,
 
- )
 
- @click.group()
 
- def cli():
 
-     """Poke coco from the command line."""
 
-     pass
 
- @cli.command()
 
- def status():
 
-     """Show the current status of the server."""
 
-     status = ServerStatus.is_server_running()
 
-     if isinstance(status, NetworkError):
 
-         print_error(f"Failed to get data from server, error {status.value}")
 
-         return
 
-     print_ok("Server is available.")
 
-     open_consumptions = ServerStatus.unsettled_consumptions()
 
-     if isinstance(open_consumptions, NetworkError):
 
-         print_error(
 
-             f"Failed to get unsettled consumptions, error {open_consumptions.value}"
 
-         )
 
-         return
 
-     click.echo(f"There are {open_consumptions.amount} unsettled consumptions.")
 
-     if open_consumptions.amount > 0:
 
-         click.echo(f"First at: {open_consumptions.first_timestamp.strftime('%c')}")
 
-         click.echo(f"Most recent at: {open_consumptions.last_timestamp.strftime('%c')}")
 
- @cli.group()
 
- def people():
 
-     pass
 
- @people.command("list")
 
- @click.option("--active/--inactive", default=None)
 
- def list_people(active: bool) -> None:
 
-     people = Person.get_all(active=active)
 
-     if isinstance(people, NetworkError):
 
-         print_error(f"Could not get people: {people.value}")
 
-         return
 
-     table = PrettyTable()
 
-     table.field_names = ["ID", "Full name", "Display name", "Active"]
 
-     table.align["ID"] = "r"
 
-     table.align["Full name"] = "l"
 
-     table.align["Display name"] = "l"
 
-     table.sortby = "Full name"
 
-     for p in people:
 
-         table.add_row([p.person_id, p.full_name, p.display_name, p.active])
 
-     print(table)
 
- @people.command("create")
 
- @click.option("--display-name", type=click.STRING)
 
- @click.argument("name", type=click.STRING)
 
- def create_person(name: str, display_name: str) -> None:
 
-     """Create a person."""
 
-     person = Person(full_name=name, display_name=display_name).create()
 
-     if isinstance(person, NetworkError):
 
-         print_error(f"Could not create Person: {person.value}")
 
-         return
 
-     print_ok(f'Created person "{name}" with ID {person.person_id}.')
 
- @people.command("rename")
 
- @click.argument("person-id", type=click.INT)
 
- @click.option("--new-full-name", type=click.STRING)
 
- @click.option("--new-display-name", type=click.STRING)
 
- def rename_person(
 
-     person_id: int, new_full_name: Optional[str], new_display_name: Optional[str],
 
- ) -> None:
 
-     person = Person.get(person_id)
 
-     if person is None:
 
-         raise click.UsageError(f"Cannot find Person {person_id}!")
 
-     if new_full_name is None and new_display_name is None:
 
-         raise click.UsageError("No new full name or display name specified!")
 
-     new_person = person.rename(
 
-         new_full_name=new_full_name, new_display_name=new_display_name
 
-     )
 
- @cli.group()
 
- def settlements():
 
-     pass
 
- @settlements.command("show")
 
- @click.argument("settlement_id", type=click.INT)
 
- def show_settlement(settlement_id: int) -> None:
 
-     """Get and view the contents of a Settlement."""
 
-     s = Settlement.get(settlement_id)
 
-     if isinstance(s, NetworkError):
 
-         print_error(f"Could not get Settlement: {s.value}")
 
-         return
 
-     output_settlement_info(s)
 
- @settlements.command("create")
 
- @click.argument("name")
 
- def create_settlement(name: str) -> None:
 
-     """Create a new Settlement."""
 
-     s = Settlement.create(name)
 
-     if isinstance(s, NetworkError):
 
-         print_error(f"Could not create Settlement: {s.value}")
 
-         return
 
-     output_settlement_info(s)
 
- def output_settlement_info(s: Settlement) -> None:
 
-     click.echo(f'Settlement {s.settlement_id}, "{s.name}"')
 
-     click.echo(f"Summary:")
 
-     for key, value in s.consumption_summary.items():
 
-         click.echo(f" - {value['count']} {value['name']} ({key})")
 
-     ct_name_by_id = {key: value["name"] for key, value in s.consumption_summary.items()}
 
-     table = PrettyTable()
 
-     table.field_names = ["Name", *ct_name_by_id.values()]
 
-     table.sortby = "Name"
 
-     table.align = "r"
 
-     table.align["Name"] = "l"  # type: ignore
 
-     zero_fields = {k: "" for k in ct_name_by_id.values()}
 
-     for item in s.per_person_counts.values():
 
-         r = {"Name": item["full_name"], **zero_fields}
 
-         for key, value in item["counts"].items():
 
-             r[ct_name_by_id[key]] = value
 
-         table.add_row(r.values())
 
-     print(table)
 
- @cli.group()
 
- def consumption_types():
 
-     pass
 
- @consumption_types.command("list")
 
- def list_consumption_types() -> None:
 
-     active = ConsumptionType.get_all(active=True)
 
-     inactive = ConsumptionType.get_all(active=False)
 
-     if isinstance(active, NetworkError) or isinstance(inactive, NetworkError):
 
-         print_error("Could not get consumption types!")
 
-         return
 
-     table = PrettyTable()
 
-     table.field_names = ["ID", "Name", "Active"]
 
-     table.sortby = "ID"
 
-     for ct in active + inactive:
 
-         table.add_row([ct.consumption_type_id, ct.name, ct.active])
 
-     print(table)
 
- @consumption_types.command("create")
 
- @click.argument("name")
 
- def create_consumption_type(name: str) -> None:
 
-     ct = ConsumptionType(name=name).create()
 
-     if not isinstance(ct, NetworkError):
 
-         print_ok(f'Created consumption type "{name}" with ID {ct.consumption_type_id}.')
 
- @consumption_types.command("activate")
 
- @click.argument("consumption_type_id", type=click.INT)
 
- def activate_consumption_type(consumption_type_id: int) -> None:
 
-     ct = ConsumptionType.get(consumption_type_id)
 
-     if isinstance(ct, NetworkError):
 
-         print_error(f"Could not get ConsumptionType: {ct.value}")
 
-         return
 
-     result = ct.set_active(True)
 
-     if not isinstance(result, NetworkError):
 
-         print_ok(
 
-             f"Consumption type {ct.consumption_type_id} ({ct.name}) is now active."
 
-         )
 
- @consumption_types.command("deactivate")
 
- @click.argument("consumption_type_id", type=click.INT)
 
- def deactivate_consumption_type(consumption_type_id: int) -> None:
 
-     ct = ConsumptionType.get(consumption_type_id)
 
-     if isinstance(ct, NetworkError):
 
-         print_error(f"Could not get ConsumptionType: {ct.value}")
 
-         return
 
-     result = ct.set_active(False)
 
-     if not isinstance(result, NetworkError):
 
-         print_ok(
 
-             f"Consumption type {ct.consumption_type_id} ({ct.name}) is now inactive."
 
-         )
 
- def print_ok(msg: str) -> None:
 
-     click.echo(click.style(msg, fg="green"))
 
- def print_error(msg: str) -> None:
 
-     click.echo(click.style(msg, fg="red", bold=True), err=True)
 
- @cli.group()
 
- @click.option("--token", required=True, envvar="AARDBEI_TOKEN")
 
- @click.option("--endpoint", default="http://localhost:3000", envvar="AARDBEI_ENDPOINT")
 
- @click.pass_context
 
- def aardbei(ctx, token: str, endpoint: str) -> None:
 
-     ctx.ensure_object(dict)
 
-     ctx.obj["AardbeiToken"] = token
 
-     ctx.obj["AardbeiEndpoint"] = endpoint
 
- @aardbei.group("activities")
 
- def aardbei_activities() -> None:
 
-     pass
 
- @aardbei_activities.command("list")
 
- @click.pass_context
 
- def aardbei_list_activities(ctx) -> None:
 
-     acts = AardbeiActivity.get_available(
 
-         token=ctx.obj["AardbeiToken"], endpoint=ctx.obj["AardbeiEndpoint"]
 
-     )
 
-     if isinstance(acts, NetworkError):
 
-         print_error(f"Could not get activities: {acts.value}")
 
-         return
 
-     table = PrettyTable()
 
-     table.field_names = ["ID", "Name"]
 
-     table.align = "l"
 
-     for a in acts:
 
-         table.add_row([a.aardbei_id, a.name])
 
-     print(table)
 
- @aardbei_activities.command("apply")
 
- @click.argument("activity_id", type=click.INT)
 
- @click.pass_context
 
- def aardbei_apply_activity(ctx, activity_id: int) -> None:
 
-     result = AardbeiActivity.apply_activity(
 
-         token=ctx.obj["AardbeiToken"],
 
-         endpoint=ctx.obj["AardbeiEndpoint"],
 
-         activity_id=activity_id,
 
-     )
 
-     if isinstance(result, NetworkError):
 
-         print_error("Failed to apply activity: {result.value}")
 
-         return
 
-     print_ok(f"Activity applied. There are now {result} active people.")
 
- @aardbei.group("people")
 
- def aardbei_people() -> None:
 
-     pass
 
- @aardbei_people.command("diff")
 
- @click.pass_context
 
- def aardbei_diff_people(ctx) -> None:
 
-     diff = AardbeiPeopleDiff.get_diff(
 
-         token=ctx.obj["AardbeiToken"], endpoint=ctx.obj["AardbeiEndpoint"]
 
-     )
 
-     if isinstance(diff, NetworkError):
 
-         print_error(f"Could not get differences: {diff.value}")
 
-         return
 
-     if diff.num_changes == 0:
 
-         print_ok("There are no changes to apply.")
 
-         return
 
-     click.echo(f"There are {diff.num_changes} pending changes:")
 
-     show_diff(diff)
 
- @aardbei_people.command("sync")
 
- @click.pass_context
 
- def aardbei_sync_people(ctx) -> None:
 
-     diff = AardbeiPeopleDiff.sync(
 
-         token=ctx.obj["AardbeiToken"], endpoint=ctx.obj["AardbeiEndpoint"]
 
-     )
 
-     if isinstance(diff, NetworkError):
 
-         print_error(f"Could not apply differences: {diff.value}")
 
-         return
 
-     if diff.num_changes == 0:
 
-         print_ok("There were no changes to apply.")
 
-         return
 
-     print_ok(f"Applied {diff.num_changes} pending changes:")
 
-     show_diff(diff)
 
- def show_diff(diff: AardbeiPeopleDiff) -> None:
 
-     for name in diff.new_people:
 
-         click.echo(f" - Create local Person for {name}")
 
-     for name in diff.link_existing:
 
-         click.echo(f" - Link local and remote people for {name}")
 
-     for name in diff.altered_name:
 
-         click.echo(f" - Process name change for {name}")
 
- if __name__ == "__main__":
 
-     cli()
 
 
  |