annoworkapi.wrapper のソースコード

from __future__ import annotations

import datetime
import logging
from collections import defaultdict
from typing import Any, Optional

from annoworkapi.actual_working_time import (
    create_actual_working_times_daily,
    get_term_start_end_from_date_for_actual_working_time,
)
from annoworkapi.api import AnnoworkApi, allow_404_error
from annoworkapi.schedule import _ExpectedWorkingHoursDict, create_schedules_daily

logger = logging.getLogger(__name__)


def _filter_actual_working_times_daily(
    actual_daily_list: list[dict[str, Any]], term_start_date: Optional[str], term_end_date: Optional[str]
) -> list[dict[str, Any]]:
    if term_start_date is None and term_end_date is None:
        return actual_daily_list

    def is_match(elm: dict[str, Any]) -> bool:
        result = True
        if term_start_date is not None:
            result = result and elm["date"] >= term_start_date
        if term_end_date is not None:
            result = result and elm["date"] <= term_end_date
        return result

    return [e for e in actual_daily_list if is_match(e)]


[ドキュメント] class Wrapper: """ AnnoworkApiのラッパー. Args: api: AnnoworkApi Instance """ def __init__(self, api: AnnoworkApi) -> None: self.api = api ################################################################################################################### # Account ################################################################################################################### @allow_404_error(logger=logger) def get_account_external_linkage_info_or_none(self, user_id: str) -> Optional[dict[str, Any]]: return self.api.get_account_external_linkage_info(user_id, log_response_with_error=False) def get_annofab_account_id_from_user_id(self, user_id: str) -> Optional[str]: info = self.get_account_external_linkage_info_or_none(user_id) if info is None: return None if "annofab" not in info["external_linkage_info"]: return None return info["external_linkage_info"]["annofab"].get("account_id") @allow_404_error(logger=logger) def get_workspace_or_none(self, workspace_id: str) -> Optional[dict[str, Any]]: return self.api.get_workspace(workspace_id, log_response_with_error=False) @allow_404_error(logger=logger) def get_workspace_tag_or_none(self, workspace_id: str, workspace_tag_id: str) -> Optional[dict[str, Any]]: return self.api.get_workspace_tag(workspace_id, workspace_tag_id, log_response_with_error=False) @allow_404_error(logger=logger) def get_job_or_none(self, workspace_id: str, job_id: str) -> Optional[dict[str, Any]]: return self.api.get_job(workspace_id, job_id, log_response_with_error=False) @allow_404_error(logger=logger) def get_job_children_or_none(self, workspace_id: str, job_id: str) -> Optional[list[dict[str, Any]]]: return self.api.get_job_children(workspace_id, job_id, log_response_with_error=False) @allow_404_error(logger=logger) def get_workspace_member_or_none(self, workspace_id: str, workspace_member_id: str) -> Optional[dict[str, Any]]: return self.api.get_workspace_member(workspace_id, workspace_member_id, log_response_with_error=False) ################################################################################################################### # actual_working_time ###################################################################################################################
[ドキュメント] def get_actual_working_times_daily( self, workspace_id: str, *, job_id: Optional[str] = None, term_start_date: Optional[str] = None, term_end_date: Optional[str] = None, tzinfo: Optional[datetime.tzinfo] = None, ) -> list[dict[str, Any]]: """ワークスペース全体の実績時間を一括取得します。実績時間は日、ジョブ、メンバ単位で集計されています。 Args: workspace_id (str): ワークスペースID (required) job_id (str): ジョブIDで絞り込みます。 term_start_date (str): 検索範囲の開始日(YYYY-MM-DD) term_end_date (str): 検索範囲の終了日(YYYY-MM-DD) tzinfo: 日付を決めるためのタイムゾーン。未指定の場合はシステムのタイムゾーンを参照します。 Returns: 日付、ジョブ、メンバ単位で集計した実績時間のlistを返します。listの要素はdictで以下のキーを持ちます。 * date * job_id * workspace_member_id * actual_working_hours """ term_start, term_end = get_term_start_end_from_date_for_actual_working_time(term_start_date, term_end_date, tzinfo=tzinfo) query_params = { "job_id": job_id, "term_start": term_start, "term_end": term_end, } tmp = self.api.get_actual_working_times(workspace_id, query_params=query_params) daily_list = create_actual_working_times_daily(tmp, tzinfo=tzinfo) return _filter_actual_working_times_daily(daily_list, term_start_date=term_start_date, term_end_date=term_end_date)
[ドキュメント] def get_actual_working_times_by_workspace_member_daily( self, workspace_id: str, workspace_member_id: str, *, term_start_date: Optional[str] = None, term_end_date: Optional[str] = None, tzinfo: Optional[datetime.tzinfo] = None, ) -> list[dict[str, Any]]: """ワークスペースメンバーに対する実績時間を一括取得します。実績時間は日、ジョブ、メンバ単位で集計されています。 Args: workspace_id (str): ワークスペースID (required) workspace_member_id (str): ワークスペースメンバーID (required) term_start_date (str): 検索範囲の開始日(YYYY-MM-DD) term_end_date (str): 検索範囲の終了日(YYYY-MM-DD) tzinfo: 日付を決めるためのタイムゾーン。未指定の場合はシステムのタイムゾーンを参照します。 Returns: 日付、ジョブ、メンバ単位で集計した実績時間のlistを返します。listの要素はdictで以下のキーを持ちます。 * date * job_id * workspace_member_id * actual_working_hours """ term_start, term_end = get_term_start_end_from_date_for_actual_working_time(term_start_date, term_end_date, tzinfo=tzinfo) query_params = { "term_start": term_start, "term_end": term_end, } tmp = self.api.get_actual_working_times_by_workspace_member(workspace_id, workspace_member_id, query_params=query_params) daily_list = create_actual_working_times_daily(tmp, tzinfo=tzinfo) return _filter_actual_working_times_daily(daily_list, term_start_date=term_start_date, term_end_date=term_end_date)
################################################################################################################### # schedule ###################################################################################################################
[ドキュメント] def get_schedules_daily( self, workspace_id: str, *, term_start: Optional[str] = None, term_end: Optional[str] = None, job_id: Optional[str] = None, ) -> list[dict[str, Any]]: """日、ジョブ、メンバ単位のアサイン時間を取得します。 Notes: 内部で `api.get_expected_working_times` を実行します。 Args: workspace_id: ワークスペースID term_start_date (str): 検索範囲の開始日(YYYY-MM-DD) term_end_date (str): 検索範囲の終了日(YYYY-MM-DD) job_id (str): 検索対象のジョブID Returns: 日、ジョブ、メンバ単位のアサイン時間のlist。listの要素は以下のキーを持ちます。 * date * job_id * workspace_member_id * assigned_working_hours """ def _get_min_max_date(s_list: list[dict[str, Any]]) -> tuple[str, str]: min_date = "9999-99-99" max_date = "0000-00-00" for schedule in s_list: min_date = min(min_date, schedule["start_date"]) max_date = max(max_date, schedule["end_date"]) return min_date, max_date schedule_list = self.api.get_schedules(workspace_id, query_params={"job_id": job_id, "term_start": term_start, "term_end": term_end}) if len(schedule_list) == 0: return [] min_date, max_date = _get_min_max_date(schedule_list) expected_working_times = self.api.get_expected_working_times(workspace_id, query_params={"term_start": min_date, "term_end": max_date}) expected_working_hours_dict: _ExpectedWorkingHoursDict = { (e["date"], e["workspace_member_id"]): e["expected_working_hours"] for e in expected_working_times if e["expected_working_hours"] > 0 } result_dict: dict[tuple[str, str, str], float] = defaultdict(float) for schedule in schedule_list: schedules_daily = create_schedules_daily(schedule, expected_working_hours_dict) for elm in schedules_daily: result_dict[(elm["date"], elm["workspace_member_id"], elm["job_id"])] += elm["assigned_working_hours"] result_list = [] for (date, tmp_workspace_member_id, tmp_job_id), assigned_working_hours in result_dict.items(): if assigned_working_hours == 0: # アサイン時間が0の情報は不要なので、出力しないようにする continue if term_start is not None and not date >= term_start: continue if term_end is not None and not date <= term_end: continue result_list.append( { "date": date, "workspace_member_id": tmp_workspace_member_id, "job_id": tmp_job_id, "assigned_working_hours": assigned_working_hours, } ) return result_list