Repository: kurusugawa-computer/annofab-cli (language: python)

Issue:
新しい統計webapiに移行する



Discussion / hints:

Fix patch:
diff --git a/annofabcli/__version__.py b/annofabcli/__version__.py
index 98fc638e..aff1b006 100644
--- a/annofabcli/__version__.py
+++ b/annofabcli/__version__.py
@@ -1,1 +1,1 @@
-__version__ = "1.53.9"
+__version__ = "1.54.0"
diff --git a/annofabcli/annotation/copy_annotation.py b/annofabcli/annotation/copy_annotation.py
index de28e7ed..85398c65 100644
--- a/annofabcli/annotation/copy_annotation.py
+++ b/annofabcli/annotation/copy_annotation.py
@@ -226,6 +226,7 @@ def copy_annotation_by_input_data(self, project_id: str, copy_target: CopyTarget
             copy_target.dest_task_id,
             copy_target.dest_input_data_id,
             src_details=anno_details,
+            account_id=self.service.api.account_id,
         )
         request_body["updated_datetime"] = dest_annotation["updated_datetime"]
         self.service.api.put_annotation(
diff --git a/annofabcli/data/logging.yaml b/annofabcli/data/logging.yaml
index 4c602cb2..d327cf36 100644
--- a/annofabcli/data/logging.yaml
+++ b/annofabcli/data/logging.yaml
@@ -16,7 +16,7 @@ loggers:
   __main__:
     level: DEBUG
   annofabapi:
-    level: DEBUG
+    level: INFO
   annofabcli:
     level: DEBUG
 root:
diff --git a/annofabcli/experimental/dashboard.py b/annofabcli/experimental/dashboard.py
deleted file mode 100644
index 530606af..00000000
--- a/annofabcli/experimental/dashboard.py
+++ /dev/null
@@ -1,623 +0,0 @@
-import argparse
-import datetime
-import itertools
-import json
-import logging
-from collections import defaultdict
-from dataclasses import dataclass
-from typing import Any, Dict, List, Optional, Tuple
-
-import annofabapi
-import dateutil
-import pandas
-from annofabapi.models import ProjectMemberRole, Task
-from annofabapi.utils import str_now
-from dataclasses_json import DataClassJsonMixin
-from dateutil.parser import parse
-from more_itertools import first_true
-
-import annofabcli
-import annofabcli.common.cli
-from annofabcli import AnnofabApiFacade
-from annofabcli.common.cli import (
-    AbstractCommandLineInterface,
-    ArgumentParser,
-    build_annofabapi_resource_and_login,
-    get_json_from_args,
-    get_wait_options_from_args,
-)
-from annofabcli.common.dataclasses import WaitOptions
-from annofabcli.common.download import DownloadingFile
-from annofabcli.common.enums import FormatArgument
-from annofabcli.common.utils import isoduration_to_hour
-from annofabcli.statistics.summarize_task_count_by_task_id import TaskStatusForSummary
-
-logger = logging.getLogger(__name__)
-
-DEFAULT_WAIT_OPTIONS = WaitOptions(interval=60, max_tries=360)
-
-
-@dataclass
-class TaskPhaseStatistics(DataClassJsonMixin):
-    date: str
-    annotation_worktime: float = 0
-    inspection_worktime: float = 0
-    acceptance_worktime: float = 0
-
-    def sum_worktime(self) -> float:
-        return self.annotation_worktime + self.inspection_worktime + self.acceptance_worktime
-
-
-@dataclass
-class MonitoredWorktime(DataClassJsonMixin):
-    """AnnoFab計測時間の詳細情報"""
-
-    sum: float
-    """合計時間[hour]"""
-    annotation: float
-    inspection: float
-    acceptance: float
-
-
-@dataclass
-class RemainingTaskCount(DataClassJsonMixin):
-    """
-    フェーズごとのタスク数
-    """
-
-    complete: int = 0
-    """完了状態のタスク数"""
-
-    annotation_not_started: int = 0
-    """一度も教師付作業されていないタスク数"""
-
-    inspection_not_started: int = 0
-    """一度も検査作業されていないタスク数"""
-
-    acceptance_not_started: int = 0
-    """一度も受入作業されていないタスク数"""
-
-    on_hold: int = 0
-    """保留状態のタスク数"""
-
-    other: int = 0
-    """休憩中/作業中/2回目以降の各フェーズの未着手状態のタスク数"""
-
-
-@dataclass
-class ProgressData(DataClassJsonMixin):
-    # task_count: TaskCount
-    # """タスク数情報"""
-
-    actual_worktime: float
-    """実績作業時間[hour]"""
-
-    task_count: int
-    """完了したタスク数"""
-
-    input_data_count: int
-    """完了したタスク配下の入力データ数"""
-
-    velocity_per_task: Optional[float]
-    """acutal_worktime/task_count"""
-
-    velocity_per_input_data: Optional[float]
-    """acutal_worktime/input_data_count"""
-
-    monitored_worktime: Optional[float] = None
-    """AnnoFabの計測作業時間[hour]"""
-
-    annotation_monitored_worktime: Optional[float] = None
-    """AnnoFabのannotation計測作業時間[hour]"""
-
-    inspection_monitored_worktime: Optional[float] = None
-    """AnnoFabのinspection計測作業時間[hour]"""
-
-    acceptance_monitored_worktime: Optional[float] = None
-    """AnnoFabのacceptance計測作業時間[hour]"""
-
-
-@dataclass
-class ResultValues(DataClassJsonMixin):
-
-    cumulation: ProgressData
-    """累計情報"""
-    today: ProgressData
-    """対象日当日の情報"""
-    week: ProgressData
-    """対象日から1週間（直前7日間）の情報"""
-
-
-@dataclass
-class Planvalues(DataClassJsonMixin):
-    plan_worktime: float
-    """予定作業時間"""
-    task_count: Optional[int]
-    """予定の完了タスク数"""
-
-
-@dataclass
-class DashboardData(DataClassJsonMixin):
-    project_id: str
-    project_title: str
-    date: str
-    """対象日（YYYY-MM-DD）"""
-    measurement_datetime: str
-    """計測日時。（2004-04-01T12:00+09:00形式）"""
-
-    remaining_task_count: RemainingTaskCount
-    """残りのタスク数"""
-    result: ResultValues
-    plan: Dict[int, Planvalues]
-    task_exhaustation_date: Optional[str]
-    """タスク枯渇予定日 TODO 綴り間違い"""
-
-
-def add_info_to_task(task: Task):
-    task["status_for_summary"] = TaskStatusForSummary.from_task(task).value
-
-
-def get_remaining_task_count_info_from_task_list(task_list: List[Task]) -> RemainingTaskCount:
-    """
-    状態ごとのタスク数を取得する。
-
-    Args:
-        task_list:
-
-    Returns:
-
-    """
-    status_list: List[str] = [e["status_for_summary"] for e in task_list]
-    tmp = pandas.Series.value_counts(status_list)
-    task_count = RemainingTaskCount.from_dict(tmp.to_dict())
-    return task_count
-
-
-def get_completed_task_count_and_input_data_count(task_list: List[Task]) -> Tuple[int, int]:
-    """
-    完了したタスク数と入力データ数を求める
-
-    Args:
-        task_list:
-
-    Returns:
-        Tuple[task_count, input_data_count]
-    """
-    task_list = [e for e in task_list if e["status_for_summary"] == TaskStatusForSummary.COMPLETE.value]
-    input_data_count = len(list(itertools.chain.from_iterable([e["input_data_id_list"] for e in task_list])))
-    task_count = len(task_list)
-    return task_count, input_data_count
-
-
-def _to_datetime_from_date(date: datetime.date) -> datetime.datetime:
-    dt = datetime.datetime.combine(date, datetime.datetime.min.time())
-    return dt.replace(tzinfo=dateutil.tz.tzlocal())
-
-
-def millisecond_to_hour(millisecond: int):
-    return millisecond / 1000 / 3600
-
-
-def get_task_list_where_updated_datetime(
-    task_list: List[Task], lower_date: datetime.date, upper_date: datetime.date
-) -> List[Task]:
-    """
-    タスクの更新日が、対象期間内であるタスク一覧を取得する。
-
-    Args:
-        task_list:
-        lower_date:
-        upper_date:
-
-    Returns:
-
-    """
-
-    def pred(task):
-        updated_datetime = parse(task["updated_datetime"])
-        return lower_datetime <= updated_datetime < upper_datetime
-
-    lower_datetime = _to_datetime_from_date(lower_date)
-    upper_datetime = _to_datetime_from_date(upper_date + datetime.timedelta(days=1))
-    return [t for t in task_list if pred(t)]
-
-
-def _get_actual_worktime_hour_from_labor(labor: Dict[str, Any]) -> float:
-    working_time_by_user = labor["values"]["working_time_by_user"]
-    if working_time_by_user is None:
-        return 0
-
-    actual_worktime = working_time_by_user.get("results")
-    if actual_worktime is None:
-        return 0
-    else:
-        return actual_worktime / 3600 / 1000
-
-
-def _get_plan_worktime_hour_from_labor(labor: Dict[str, Any]) -> float:
-    working_time_by_user = labor["values"]["working_time_by_user"]
-    if working_time_by_user is None:
-        return 0
-
-    actual_worktime = working_time_by_user.get("plans")
-    if actual_worktime is None:
-        return 0
-    else:
-        return actual_worktime / 3600 / 1000
-
-
-def _get_today_info(
-    today: str,
-    task_list: List[Task],
-    actual_worktime_dict: Dict[str, float],
-    task_phase_statistics: List[TaskPhaseStatistics],
-) -> ProgressData:
-    dt_today = datetime.datetime.strptime(today, "%Y-%m-%d").date()
-    task_list_for_day = get_task_list_where_updated_datetime(task_list, lower_date=dt_today, upper_date=dt_today)
-    today_monitor_worktime_info = get_monitored_worktime(
-        task_phase_statistics, lower_date=dt_today, upper_date=dt_today
-    )
-    task_count, input_data_count = get_completed_task_count_and_input_data_count(task_list_for_day)
-    actual_worktime = actual_worktime_dict.get(today, 0)
-    today_info = ProgressData(
-        task_count=task_count,
-        input_data_count=input_data_count,
-        actual_worktime=actual_worktime,
-        velocity_per_task=actual_worktime / task_count if task_count > 0 else None,
-        velocity_per_input_data=actual_worktime / input_data_count if input_data_count > 0 else None,
-    )
-    if today_monitor_worktime_info is not None:
-        today_info.monitored_worktime = today_monitor_worktime_info.sum
-        today_info.annotation_monitored_worktime = today_monitor_worktime_info.annotation
-        today_info.inspection_monitored_worktime = today_monitor_worktime_info.inspection
-        today_info.acceptance_monitored_worktime = today_monitor_worktime_info.acceptance
-    return today_info
-
-
-def _get_week_info(
-    today: str,
-    task_list: List[Task],
-    actual_worktime_dict: Dict[str, float],
-    task_phase_statistics: List[TaskPhaseStatistics],
-) -> ProgressData:
-    dt_today = datetime.datetime.strptime(today, "%Y-%m-%d").date()
-    week_ago = dt_today - datetime.timedelta(days=6)
-    task_list_for_week = get_task_list_where_updated_datetime(task_list, lower_date=week_ago, upper_date=dt_today)
-    week_monitor_worktime_info = get_monitored_worktime(task_phase_statistics, lower_date=week_ago, upper_date=dt_today)
-    task_count, input_data_count = get_completed_task_count_and_input_data_count(task_list_for_week)
-    actual_worktime = get_worktime_for_period(actual_worktime_dict, lower_date=week_ago, upper_date=dt_today)
-
-    seven_days_info = ProgressData(
-        task_count=task_count,
-        input_data_count=input_data_count,
-        actual_worktime=actual_worktime,
-        velocity_per_task=actual_worktime / task_count if task_count > 0 else None,
-        velocity_per_input_data=actual_worktime / input_data_count if input_data_count > 0 else None,
-    )
-    if week_monitor_worktime_info is not None:
-        seven_days_info.monitored_worktime = week_monitor_worktime_info.sum
-        seven_days_info.annotation_monitored_worktime = week_monitor_worktime_info.annotation
-        seven_days_info.inspection_monitored_worktime = week_monitor_worktime_info.inspection
-        seven_days_info.acceptance_monitored_worktime = week_monitor_worktime_info.acceptance
-    return seven_days_info
-
-
-def get_worktime_for_period(worktime_dict: Dict[str, float], lower_date: datetime.date, upper_date: datetime.date):
-    sum_worktime = 0.0
-    for dt in pandas.date_range(start=lower_date, end=upper_date):
-        str_date = str(dt.date())
-        sum_worktime += worktime_dict.get(str_date, 0.0)
-    return sum_worktime
-
-
-def get_monitored_worktime(
-    task_phase_statistics: List[TaskPhaseStatistics], lower_date: datetime.date, upper_date: datetime.date
-) -> Optional[MonitoredWorktime]:
-    upper_stat = first_true(task_phase_statistics, pred=lambda e: e.date == str(upper_date))
-    lower_stat = first_true(
-        task_phase_statistics, pred=lambda e: e.date == str(lower_date - datetime.timedelta(days=1))
-    )
-    if upper_stat is None or lower_stat is None:
-        logger.debug(f"{lower_date} 〜 {upper_date} 期間のmonitor_worktimeを算出できませんでした。")
-        return None
-
-    return MonitoredWorktime(
-        sum=upper_stat.sum_worktime() - lower_stat.sum_worktime(),
-        annotation=upper_stat.annotation_worktime - lower_stat.annotation_worktime,
-        inspection=upper_stat.inspection_worktime - lower_stat.inspection_worktime,
-        acceptance=upper_stat.acceptance_worktime - lower_stat.acceptance_worktime,
-    )
-
-
-def _get_cumulation_info(task_list: List[Task], actual_worktime_dict: Dict[str, float]) -> ProgressData:
-    task_count, input_data_count = get_completed_task_count_and_input_data_count(task_list)
-    actual_worktime = sum(actual_worktime_dict.values())
-
-    return ProgressData(
-        task_count=task_count,
-        input_data_count=input_data_count,
-        monitored_worktime=sum([t["worktime_hour"] for t in task_list]),
-        actual_worktime=actual_worktime,
-        velocity_per_task=actual_worktime / task_count if task_count > 0 else None,
-        velocity_per_input_data=actual_worktime / input_data_count if input_data_count > 0 else None,
-    )
-
-
-def _get_plan_value(
-    plan_worktime_dict: Dict[str, float],
-    dt_today: datetime.date,
-    days: int,
-    velocity_per_task: Optional[float],
-) -> Planvalues:
-    dt_from_date = dt_today + datetime.timedelta(days=1)
-    dt_end_date = dt_today + datetime.timedelta(days=days)
-
-    plan_worktime = get_worktime_for_period(plan_worktime_dict, lower_date=dt_from_date, upper_date=dt_end_date)
-    task_count = (
-        int(plan_worktime / velocity_per_task) if velocity_per_task is not None and velocity_per_task > 0 else None
-    )
-    return Planvalues(plan_worktime=plan_worktime, task_count=task_count)
-
-
-def get_task_exhaustation_date(
-    plan_worktime_dict: Dict[str, float], annotation_not_started: int, velocity_per_task: float
-) -> Optional[str]:
-    """
-    タスクの枯渇予定日を求める。
-    教師付されていないタスク数がすでに０ならば、Noneを返す。
-
-    Args:
-        plan_worktime_dict:
-        annotation_not_started:
-        velocity_per_task:
-
-    Returns:
-
-    """
-    if annotation_not_started <= 0 or velocity_per_task <= 0:
-        return None
-
-    remaining_task: float = annotation_not_started
-    for date in sorted(plan_worktime_dict.keys()):
-        plan_worktime = plan_worktime_dict[date]
-        task_count = plan_worktime / velocity_per_task
-        remaining_task -= task_count
-        if remaining_task <= 0:
-            return date
-    return None
-
-
-def create_plan_values(
-    plan_worktime_dict: Dict[str, float], velocity_per_task: Optional[float], today: str
-) -> Dict[int, Planvalues]:
-    dt_today = datetime.datetime.strptime(today, "%Y-%m-%d").date()
-    return {
-        7: _get_plan_value(plan_worktime_dict, dt_today=dt_today, days=7, velocity_per_task=velocity_per_task),
-        14: _get_plan_value(plan_worktime_dict, dt_today=dt_today, days=14, velocity_per_task=velocity_per_task),
-    }
-
-
-class PrintDashBoardMain:
-    def __init__(self, service: annofabapi.Resource):
-        self.service = service
-        self.facade = AnnofabApiFacade(service)
-
-    def get_task_phase_statistics(self, project_id: str) -> List[TaskPhaseStatistics]:
-        """
-        フェーズごとの累積作業時間をCSVに出力するための dict 配列を作成する。
-
-        Args:
-            project_id:
-
-        Returns:
-            フェーズごとの累積作業時間に対応するdict配列
-
-        """
-        task_phase_statistics = self.service.wrapper.get_task_phase_statistics(project_id)
-        row_list: List[TaskPhaseStatistics] = []
-        for stat_by_date in task_phase_statistics:
-            elm = {"date": stat_by_date["date"]}
-            for phase_stat in stat_by_date["phases"]:
-                phase = phase_stat["phase"]
-                worktime_hour = isoduration_to_hour(phase_stat["worktime"])
-                elm[f"{phase}_worktime"] = worktime_hour
-            row_list.append(TaskPhaseStatistics.from_dict(elm))
-        return row_list
-
-    def get_actual_worktime_dict(self, project_id: str, date: str) -> Dict[str, float]:
-        """
-        日毎のプロジェクト全体の実績作業時間を取得する。
-
-        Args:
-            project_id:
-            date: 対象期間の終了日
-
-        Returns:
-            key:date, value:実績作業時間のdict
-
-        """
-        labor_list, _ = self.service.api.get_labor_control({"project_id": project_id, "to": date})
-        actual_worktime_dict: Dict[str, float] = defaultdict(float)
-        for labor in labor_list:
-            date = labor["date"]
-            actual_worktime = _get_actual_worktime_hour_from_labor(labor)
-            actual_worktime_dict[date] += actual_worktime
-
-        return actual_worktime_dict
-
-    def get_plan_worktime_dict(self, project_id: str, today: str, days: Optional[int] = None) -> Dict[str, float]:
-        """
-        日毎のプロジェクト全体の予定作業時間を取得する。
-
-        Args:
-            project_id:
-            date: 対象期間の終了日
-
-        Returns:
-            key:date, value: 予定作業時間のdict
-
-        """
-        dt_today = datetime.datetime.strptime(today, "%Y-%m-%d").date()
-        dt_from_date = dt_today + datetime.timedelta(days=1)
-        end_date = str(dt_today + datetime.timedelta(days=days)) if days is not None else None
-
-        labor_list, _ = self.service.api.get_labor_control(
-            {"project_id": project_id, "from": str(dt_from_date), "to": end_date}
-        )
-        plan_worktime_dict: Dict[str, float] = defaultdict(float)
-        for labor in labor_list:
-            date = labor["date"]
-            plan_worktime = _get_plan_worktime_hour_from_labor(labor)
-            plan_worktime_dict[date] += plan_worktime
-
-        return plan_worktime_dict
-
-    def create_result_values(self, project_id: str, date: str, task_list: List[Task]) -> ResultValues:
-        """
-        実績情報を生成する。
-
-        Args:
-            task_list:
-            date: タスク数　集計対象日
-
-        Returns:
-
-        """
-        for task in task_list:
-            task["status_for_summary"] = TaskStatusForSummary.from_task(task).value
-            task["worktime_hour"] = millisecond_to_hour(task["work_time_span"])
-
-        actual_worktime_dict = self.get_actual_worktime_dict(project_id, date)
-        task_phase_statistics = self.get_task_phase_statistics(project_id)
-
-        cumulation_info = _get_cumulation_info(task_list, actual_worktime_dict)
-        today_info = _get_today_info(
-            today=date,
-            task_list=task_list,
-            actual_worktime_dict=actual_worktime_dict,
-            task_phase_statistics=task_phase_statistics,
-        )
-        week_info = _get_week_info(
-            today=date,
-            task_list=task_list,
-            actual_worktime_dict=actual_worktime_dict,
-            task_phase_statistics=task_phase_statistics,
-        )
-        return ResultValues(cumulation=cumulation_info, today=today_info, week=week_info)
-
-    def create_dashboard_data(self, project_id: str, date: str, task_list: List[Task]) -> DashboardData:
-        project_title = self.facade.get_project_title(project_id)
-        result = self.create_result_values(project_id=project_id, date=date, task_list=task_list)
-        remaining_task_count = get_remaining_task_count_info_from_task_list(task_list)
-        plan_worktime_dict = self.get_plan_worktime_dict(project_id, today=date)
-        velocity_per_task = result.week.velocity_per_task
-
-        task_exhaustation_date = (
-            get_task_exhaustation_date(
-                plan_worktime_dict=plan_worktime_dict,
-                annotation_not_started=remaining_task_count.annotation_not_started,
-                velocity_per_task=velocity_per_task,
-            )
-            if velocity_per_task is not None
-            else None
-        )
-
-        dashboard_info = DashboardData(
-            project_id=project_id,
-            project_title=project_title,
-            date=date,
-            measurement_datetime=str_now(),
-            remaining_task_count=remaining_task_count,
-            result=result,
-            plan=create_plan_values(plan_worktime_dict, velocity_per_task=velocity_per_task, today=date),
-            task_exhaustation_date=task_exhaustation_date,
-        )
-        return dashboard_info
-
-
-class DashBoard(AbstractCommandLineInterface):
-    def print_summarize_task_count(self, target_dict: dict) -> None:
-        annofabcli.utils.print_according_to_format(
-            target_dict,
-            arg_format=FormatArgument.JSON,
-            output=self.output,
-        )
-
-    def main(self):
-        args = self.args
-        project_id = args.project_id
-        super().validate_project(project_id, [ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER])
-
-        if args.task_json is not None:
-            task_json_path = args.task_json
-        else:
-            wait_options = get_wait_options_from_args(get_json_from_args(args.wait_options), DEFAULT_WAIT_OPTIONS)
-            cache_dir = annofabcli.utils.get_cache_dir()
-            task_json_path = cache_dir / f"{project_id}-task.json"
-
-            downloading_obj = DownloadingFile(self.service)
-            downloading_obj.download_task_json(
-                project_id, dest_path=str(task_json_path), is_latest=args.latest, wait_options=wait_options
-            )
-
-        with open(task_json_path, encoding="utf-8") as f:
-            task_list = json.load(f)
-
-        main_obj = PrintDashBoardMain(self.service)
-
-        dashboard_date = main_obj.create_dashboard_data(project_id, date=args.date, task_list=task_list)
-        annofabcli.utils.print_according_to_format(
-            dashboard_date.to_dict(),
-            arg_format=FormatArgument(self.str_format),
-            output=self.output,
-        )
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    argument_parser = ArgumentParser(parser)
-
-    argument_parser.add_project_id()
-    parser.add_argument(
-        "--task_json",
-        type=str,
-        help="タスク情報が記載されたJSONファイルのパスを指定してます。JSONファイルは ``$ annofabcli project download task`` コマンドで取得できます。"
-        "指定しない場合は、AnnoFabからタスク全件ファイルをダウンロードします。",
-    )
-
-    parser.add_argument("--date", type=str, required=True, help="``YYYY-MM-DD`` 形式で実績の対象日を指定してください。")
-
-    parser.add_argument(
-        "--latest", action="store_true", help="最新のタスク一覧ファイルを参照します。このオプションを指定すると、タスク一覧ファイルを更新するのに数分待ちます。"
-    )
-
-    parser.add_argument(
-        "--wait_options",
-        type=str,
-        help="タスク一覧ファイルの更新が完了するまで待つ際のオプションを、JSON形式で指定してください。"
-        " ``file://`` を先頭に付けるとjsonファイルを指定できます。"
-        'デフォルは ``{"interval":60, "max_tries":360}`` です。'
-        "``interval`` :完了したかを問い合わせる間隔[秒], "
-        "``max_tires`` :完了したかの問い合わせを最大何回行うか。",
-    )
-
-    argument_parser.add_format([FormatArgument.PRETTY_JSON, FormatArgument.JSON], default=FormatArgument.PRETTY_JSON)
-    argument_parser.add_output()
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def main(args):
-    service = build_annofabapi_resource_and_login(args)
-    facade = AnnofabApiFacade(service)
-    DashBoard(service, facade, args).main()
-
-
-def add_parser(subparsers: argparse._SubParsersAction):
-    subcommand_name = "dashboard"
-    subcommand_help = "ダッシュボードとなる情報（タスク数など）をJSON形式で出力します。"
-    description = "ダッシュボードとなる情報（タスク数など）をJSON形式で出力します。"
-    epilog = "オーナロールを持つユーザで実行してください。"
-    parser = annofabcli.common.cli.add_parser(
-        subparsers, subcommand_name, subcommand_help, description=description, epilog=epilog
-    )
-    parse_args(parser)
diff --git a/annofabcli/experimental/list_labor_worktime.py b/annofabcli/experimental/list_labor_worktime.py
deleted file mode 100644
index 6ecad980..00000000
--- a/annofabcli/experimental/list_labor_worktime.py
+++ /dev/null
@@ -1,683 +0,0 @@
-import argparse
-import logging
-import multiprocessing
-import sys
-from dataclasses import dataclass
-from enum import Enum
-from functools import partial
-from pathlib import Path
-from typing import List, Optional, Tuple
-
-import annofabapi
-import numpy
-import pandas
-from dataclasses_json import DataClassJsonMixin
-
-import annofabcli
-import annofabcli.common.cli
-from annofabcli import AnnofabApiFacade
-from annofabcli.common.cli import (
-    COMMAND_LINE_ERROR_STATUS_CODE,
-    AbstractCommandLineInterface,
-    ArgumentParser,
-    build_annofabapi_resource_and_login,
-    get_list_from_args,
-)
-from annofabcli.common.utils import isoduration_to_hour, print_csv
-
-logger = logging.getLogger(__name__)
-
-
-@dataclass
-class DailyMonitoredWorktime(DataClassJsonMixin):
-    """日ごとの計測作業時間情報"""
-
-    project_id: str
-    account_id: str
-    date: str
-    worktime_monitored: float
-    """Annofabの計測作業時間[hour]"""
-
-
-@dataclass
-class DailyLaborWorktime(DataClassJsonMixin):
-    """日ごとの実績作業時間と予定作業時間の情報"""
-
-    project_id: str
-    account_id: str
-    date: str
-    worktime_actual: float
-    """実績作業時間[hour]"""
-    worktime_planned: float
-    """予定作業時間[hour]"""
-    working_description: Optional[str]
-
-
-class FormatTarget(Enum):
-    DETAILS = "details"
-    """日毎・人毎の詳細な値を出力する"""
-    TOTAL_BY_USER = "total_by_user"
-    """人毎の作業時間を出力する"""
-    TOTAL_BY_PROJECT = "total_by_project"
-    """プロジェクト毎の作業時間を出力する"""
-    TOTAL = "total"
-    """合計の作業時間を出力する"""
-    COLUMN_LIST = "column_list"
-    """列固定で詳細な値を出力する"""
-    COLUMN_LIST_PER_PROJECT = "column_list_per_project"
-    """列固定で、日、メンバ、AnnoFabプロジェクトごとの作業時間を出力する"""
-    INTERMEDIATE = "intermediate"
-    """中間ファイル。このファイルからいろんな形式に変換できる。"""
-
-
-DEFAULT_TO_REPLACE_FOR_VALUE = {numpy.inf: "--", numpy.nan: "--"}
-
-
-def create_df_with_format_column_list_per_project(df_actual_times: pandas.DataFrame) -> pandas.DataFrame:
-    """`--format column_list_per_project`に対応するDataFrameを生成する。
-
-    Args:
-        df (pd.DataFrame): [description]
-
-    Returns:
-        pd.DataFrame: [description]
-    """
-    df = df_actual_times.copy()
-
-    # 元のコマンドの出力結果にできるだけ近づける
-
-    df["activity_rate"] = df["worktime_actual"] / df["worktime_planned"]
-    df["monitor_rate"] = df["worktime_monitored"] / df["worktime_actual"]
-
-    return (
-        df[
-            [
-                "date",
-                "project_id",
-                "project_title",
-                "user_id",
-                "username",
-                "biography",
-                "worktime_planned",
-                "worktime_actual",
-                "worktime_monitored",
-                "activity_rate",
-                "monitor_rate",
-                "working_description",
-            ]
-        ]
-        .round(2)
-        .replace(DEFAULT_TO_REPLACE_FOR_VALUE)
-    )
-
-
-def create_df_with_format_total_by_user(df_intermediate: pandas.DataFrame) -> pandas.DataFrame:
-    """`--format total_by_user`に対応するDataFrameを生成する。
-
-    Args:
-        df (pd.DataFrame): 中間出力用のDataFrame
-
-    Returns:
-        pd.DataFrame: `--format total_by_user`に対応するDataFrame.user_idの辞書順(大文字小文字を区別しない).
-    """
-    df = df_intermediate.groupby("user_id")[["worktime_planned", "worktime_actual", "worktime_monitored"]].sum()
-    df_user = df_intermediate.groupby("user_id").first()[["username", "biography"]]
-    df = df.join(df_user)
-
-    df["activity_rate"] = df["worktime_actual"] / df["worktime_planned"]
-    df["monitor_rate"] = df["worktime_monitored"] / df["worktime_actual"]
-    df["monitor_diff"] = df["worktime_actual"] - df["worktime_monitored"]
-
-    df.sort_index(key=lambda e: e.str.lower(), inplace=True)
-    df.reset_index(inplace=True)
-    return (
-        df[
-            [
-                "user_id",
-                "username",
-                "biography",
-                "worktime_planned",
-                "worktime_actual",
-                "worktime_monitored",
-                "activity_rate",
-                "monitor_rate",
-                "monitor_diff",
-            ]
-        ]
-        .round(2)
-        .replace(DEFAULT_TO_REPLACE_FOR_VALUE)
-    )
-
-
-def create_df_with_format_total_by_project(df_intermediate: pandas.DataFrame) -> pandas.DataFrame:
-    """`--format total_by_project`に対応するDataFrameを生成する。
-
-    Args:
-        df (pd.DataFrame): 中間出力用のDataFrame
-
-    Returns:
-        pd.DataFrame: `--format total_by_project`に対応するDataFrame。project_titleの辞書順(大文字小文字を区別しない).
-    """
-
-    df = df_intermediate.groupby("project_id")[["worktime_planned", "worktime_actual", "worktime_monitored"]].sum()
-    df_project = df_intermediate.groupby("project_id").first()[["project_title"]]
-    df = df.join(df_project)
-
-    df["activity_rate"] = df["worktime_actual"] / df["worktime_planned"]
-    df["monitor_rate"] = df["worktime_monitored"] / df["worktime_actual"]
-    df["monitor_diff"] = df["worktime_actual"] - df["worktime_monitored"]
-
-    df.reset_index(inplace=True)
-    return (
-        df[
-            [
-                "project_id",
-                "project_title",
-                "worktime_planned",
-                "worktime_actual",
-                "worktime_monitored",
-                "activity_rate",
-                "monitor_rate",
-                "monitor_diff",
-            ]
-        ]
-        .round(2)
-        .replace(DEFAULT_TO_REPLACE_FOR_VALUE)
-        .sort_values(by=["project_title"], key=lambda e: e.str.lower())
-    )
-
-
-def create_df_with_format_column_list(df_intermediate: pandas.DataFrame) -> pandas.DataFrame:
-    """`--format column_list`に対応するDataFrameを生成する。
-    日ごと、ユーザごとに、作業時間を出力する。
-
-    Args:
-        df (pd.DataFrame): [description]
-
-    Returns:
-        pd.DataFrame: `--format column_list`に対応するDataFrame
-    """
-    df = df_intermediate.groupby(["date", "user_id"])[
-        ["worktime_actual", "worktime_monitored", "worktime_planned"]
-    ].sum()
-    df_user = df_intermediate.groupby("user_id").first()[["username", "biography"]]
-    df = df.join(df_user)
-
-    df["activity_rate"] = df["worktime_actual"] / df["worktime_planned"]
-    df["monitor_rate"] = df["worktime_monitored"] / df["worktime_actual"]
-
-    df.reset_index(inplace=True)
-    return (
-        df[
-            [
-                "date",
-                "user_id",
-                "username",
-                "biography",
-                "worktime_planned",
-                "worktime_actual",
-                "worktime_monitored",
-                "activity_rate",
-                "monitor_rate",
-            ]
-        ]
-        .round(2)
-        .replace(DEFAULT_TO_REPLACE_FOR_VALUE)
-    )
-
-
-def create_df_with_format_total(df_intermediate: pandas.DataFrame) -> pandas.DataFrame:
-    """`--format total`に対応するDataFrameを生成する。
-    1行のみのCSV
-
-    Args:
-        df (pd.DataFrame): [description]
-
-    Returns:
-        pd.DataFrame: `--format total`に対応するDataFrame
-    """
-    df = pandas.DataFrame([df_intermediate[["worktime_actual", "worktime_planned", "worktime_monitored"]].sum()])
-
-    df["activity_rate"] = df["worktime_actual"] / df["worktime_planned"]
-    df["monitor_rate"] = df["worktime_monitored"] / df["worktime_actual"]
-    df["monitor_diff"] = df["worktime_actual"] - df["worktime_monitored"]
-
-    return (
-        df[
-            [
-                "worktime_planned",
-                "worktime_actual",
-                "worktime_monitored",
-                "activity_rate",
-                "monitor_rate",
-                "monitor_diff",
-            ]
-        ]
-        .round(2)
-        .replace(DEFAULT_TO_REPLACE_FOR_VALUE)
-    )
-
-
-def create_df_with_format_details(
-    df_intermediate: pandas.DataFrame, insert_sum_row: bool = True, insert_sum_column: bool = True
-) -> pandas.DataFrame:
-    """`--format details`に対応するDataFrameを生成する。
-
-    Args:
-        df (pd.DataFrame): 中間出力用のDataFrame
-        insert_sum_row: 合計行を追加する
-        insert_sum_column: 合計列を追加する
-
-    Returns:
-        pd.DataFrame: `--format details`に対応するDataFrame.行方向は日付順、列方向はuser_idの辞書順(大文字小文字を区別しない).
-
-    """
-    SUM_COLUMN_NAME = "総合計"
-    SUM_ROW_NAME = "合計"
-
-    # 注意：同姓同名だった場合、正しく集計されない
-    df = df_intermediate.groupby(["date", "username"])[
-        ["worktime_actual", "worktime_monitored", "worktime_planned"]
-    ].sum()
-
-    if insert_sum_column:
-        df_sum_by_date = df_intermediate.groupby(["date"])[
-            ["worktime_actual", "worktime_monitored", "worktime_planned"]
-        ].sum()
-        # 列名が"総合計"になるように、indexを変更する
-        df_sum_by_date.index = [(date, SUM_COLUMN_NAME) for date in df_sum_by_date.index]
-
-        df = df.append(df_sum_by_date)
-
-    # ヘッダが [user_id, value] になるように設定する
-    df2 = df.stack().unstack([1, 2])
-
-    # 日付が連続になるようにする
-    not_exists_date_set = {str(e.date()) for e in pandas.date_range(start=min(df2.index), end=max(df2.index))} - set(
-        df2.index
-    )
-    df2 = df2.append([pandas.Series(name=date, dtype="float64") for date in not_exists_date_set], sort=True)
-    df2.sort_index(inplace=True)
-    # 作業時間がNaNの場合は0に置換する
-    df2.replace(
-        {
-            col: {numpy.nan: 0}
-            for col in df2.columns
-            if col[1] in ["worktime_actual", "worktime_monitored", "worktime_planned"]
-        },
-        inplace=True,
-    )
-
-    # user_idの辞書順（大文字小文字区別しない）のユーザのDataFrameを生成する。
-    df_user = (
-        df_intermediate[["user_id", "username", "biography"]]
-        .drop_duplicates()
-        .set_index("user_id")
-        .sort_index(key=lambda x: x.str.lower())
-    )
-
-    username_list = list(df_user["username"])
-    if insert_sum_column:
-        username_list = [SUM_COLUMN_NAME] + username_list
-
-    if insert_sum_row:
-        # 先頭行に合計を追加する
-        tmp_sum_row = df2.sum()
-        tmp_sum_row.name = SUM_ROW_NAME
-        df2 = pandas.concat([pandas.DataFrame([tmp_sum_row]), df2])
-
-    # activity_rate,monitor_rateの追加。PerformanceWarningが出ないようにするため、まとめて列を追加する
-    added_column_list = []
-    for username in username_list:
-        s1 = pandas.Series(
-            df2[(username, "worktime_actual")] / df2[(username, "worktime_planned")], name=(username, "activity_rate")
-        )
-        s2 = pandas.Series(
-            df2[(username, "worktime_monitored")] / df2[(username, "worktime_actual")], name=(username, "monitor_rate")
-        )
-        added_column_list.extend([s1, s2])
-
-    df_added_rate = pandas.concat(added_column_list, axis="columns")
-    df2 = pandas.concat([df2, df_added_rate], axis="columns")
-
-    # 比率がNaNの場合は"--"に置換した上で、列の順番を変える。
-    df2 = df2.round(2).replace(
-        {col: DEFAULT_TO_REPLACE_FOR_VALUE for col in df2.columns if col[1] in ["activity_rate", "monitor_rate"]},
-    )[
-        [
-            (m, v)
-            for m in username_list
-            for v in ["worktime_planned", "worktime_actual", "worktime_monitored", "activity_rate", "monitor_rate"]
-        ]
-    ]
-
-    # date列を作る
-    df2.reset_index(inplace=True)
-    return df2
-
-
-def create_df_from_intermediate(
-    df_intermediate: pandas.DataFrame,
-    format_target: FormatTarget,
-):
-    """中間ファイルから、formatに従ったDataFrameを生成します。"""
-
-    if format_target == FormatTarget.COLUMN_LIST_PER_PROJECT:
-        df_output = create_df_with_format_column_list_per_project(df_intermediate)
-
-    elif format_target == FormatTarget.COLUMN_LIST:
-        df_output = create_df_with_format_column_list(df_intermediate)
-
-    elif format_target == FormatTarget.TOTAL_BY_USER:
-        df_output = create_df_with_format_total_by_user(df_intermediate)
-
-    elif format_target == FormatTarget.TOTAL_BY_PROJECT:
-        df_output = create_df_with_format_total_by_project(df_intermediate)
-
-    elif format_target == FormatTarget.TOTAL:
-        df_output = create_df_with_format_total(df_intermediate)
-
-    elif format_target == FormatTarget.DETAILS:
-        df_output = create_df_with_format_details(df_intermediate)
-
-    elif format_target == FormatTarget.INTERMEDIATE:
-        df_output = df_intermediate
-
-    else:
-        raise RuntimeError(f"format_target={format_target} が不正です。")
-    return df_output
-
-
-def filter_df_intermediate(
-    df_intermediate: pandas.DataFrame,
-    *,
-    project_id_list: Optional[List[str]] = None,
-    user_id_list: Optional[List[str]] = None,
-    start_date: Optional[str] = None,
-    end_date: Optional[str] = None,
-) -> pandas.DataFrame:
-    if project_id_list is not None:
-        df_intermediate = df_intermediate[df_intermediate["project_id"].isin(set(project_id_list))]
-    if user_id_list is not None:
-        df_intermediate = df_intermediate[df_intermediate["user_id"].isin(set(user_id_list))]
-    if start_date is not None:
-        df_intermediate = df_intermediate[df_intermediate["date"] >= start_date]
-    if end_date is not None:
-        df_intermediate = df_intermediate[df_intermediate["date"] <= end_date]
-
-    return df_intermediate
-
-
-class ListLaborWorktimeMain:
-    def __init__(self, service: annofabapi.Resource):
-        self.service = service
-        self.facade = AnnofabApiFacade(service)
-
-    def _get_monitored_worktime(self, project_id: str, start_date: str, end_date: str) -> List[DailyMonitoredWorktime]:
-        """計測作業時間の情報を取得
-
-        Args:
-            project_id: Annofab プロジェクトのproject_id
-            start_date (str): [description]
-            end_date (str): [description]
-        """
-        account_statistics = self.service.wrapper.get_account_statistics(project_id)
-
-        result = []
-        for account_info in account_statistics:
-            account_id = account_info["account_id"]
-            histories = account_info["histories"]
-            for history in histories:
-                worktime_hour = isoduration_to_hour(history["worktime"])
-                if start_date <= history["date"] <= end_date and worktime_hour > 0:
-                    result.append(
-                        DailyMonitoredWorktime(
-                            project_id=project_id,
-                            account_id=account_id,
-                            date=history["date"],
-                            worktime_monitored=worktime_hour,
-                        )
-                    )
-
-        return result
-
-    def _get_labor_worktime(self, project_id: str, start_date: str, end_date: str) -> List[DailyLaborWorktime]:
-
-        labor_list = self.service.wrapper.get_labor_control_worktime(
-            project_id=project_id, from_date=start_date, to_date=end_date
-        )
-
-        new_labor_list: List[DailyLaborWorktime] = []
-        for labor in labor_list:
-            new_labor = DailyLaborWorktime(
-                project_id=labor["project_id"],
-                account_id=labor["account_id"],
-                date=labor["date"],
-                worktime_actual=labor["actual_worktime"] if labor["actual_worktime"] is not None else 0,
-                worktime_planned=labor["plan_worktime"] if labor["plan_worktime"] is not None else 0,
-                working_description=labor["working_description"],
-            )
-
-            if new_labor.worktime_actual > 0 or new_labor.worktime_planned > 0:
-                new_labor_list.append(new_labor)
-        return new_labor_list
-
-    def create_intermediate_df_for_one_project(
-        self, project_id: str, *, start_date: str, end_date: str, project_index: Optional[int] = None
-    ) -> pandas.DataFrame:
-
-        OUTPUT_COLUMNS = [
-            "date",
-            "project_id",
-            "project_title",
-            "account_id",
-            "user_id",
-            "username",
-            "biography",
-            "worktime_planned",
-            "worktime_actual",
-            "worktime_monitored",
-            "working_description",
-        ]
-
-        project, _ = self.service.api.get_project(project_id)
-
-        logging_prefix = f"{project_index+1} 件目" if project_index is not None else ""
-        logger.debug(f"{logging_prefix}: project_id='{project_id}', project_title='{project['title']}'の作業時間情報を取得します。")
-        labor_worktime = self._get_labor_worktime(project_id=project_id, start_date=start_date, end_date=end_date)
-        monitored_worktime = self._get_monitored_worktime(project_id, start_date=start_date, end_date=end_date)
-        project_member_list = self.service.wrapper.get_all_project_members(
-            project_id, query_params={"include_inactive_member": ""}
-        )
-
-        df_labor_worktime = pandas.DataFrame(
-            labor_worktime,
-            columns=["project_id", "date", "account_id", "worktime_actual", "worktime_planned", "working_description"],
-        )
-        df_monitored_worktime = pandas.DataFrame(
-            monitored_worktime, columns=["project_id", "date", "account_id", "worktime_monitored"]
-        )
-        df_project_member = pandas.DataFrame(
-            project_member_list, columns=["account_id", "user_id", "username", "biography"]
-        )
-        df_merged = pandas.merge(
-            df_labor_worktime, df_monitored_worktime, how="outer", on=["date", "project_id", "account_id"]
-        )
-        df_merged.fillna({"worktime_actual": 0, "worktime_planned": 0, "worktime_monitored": 0}, inplace=True)
-
-        df_merged["project_title"] = project["title"]
-        df = pandas.merge(
-            df_merged,
-            df_project_member,
-            how="left",
-            on=["account_id"],
-        )
-        return df[OUTPUT_COLUMNS].sort_values(["date"])
-
-    def _create_intermediate_df_for_one_project_wrapper(
-        self,
-        tpl: Tuple[int, str],
-        *,
-        start_date: str,
-        end_date: str,
-    ):
-        project_index, project_id = tpl
-        return self.create_intermediate_df_for_one_project(
-            project_id=project_id,
-            start_date=start_date,
-            end_date=end_date,
-            project_index=project_index,
-        )
-
-    def create_intermediate_df(
-        self, project_id_list: List[str], *, start_date: str, end_date: str, parallelism: Optional[int] = None
-    ) -> pandas.DataFrame:
-        """中間ファイルの元になるDataFrameを出力する。"""
-        df_list = []
-        logger.info(f"{len(project_id_list)} 件のプロジェクトの作業時間情報を取得します。")
-
-        # 集計値を出力するので、1つでも作業時間情報の取得に失敗したら終了するようにする。
-
-        if parallelism is not None:
-            partial_func = partial(
-                self._create_intermediate_df_for_one_project_wrapper,
-                start_date=start_date,
-                end_date=end_date,
-            )
-            with multiprocessing.Pool(parallelism) as pool:
-                df_list = pool.map(partial_func, enumerate(project_id_list))
-
-        else:
-            # 逐次処理
-            for project_index, project_id in enumerate(project_id_list):
-                tmp_df = self.create_intermediate_df_for_one_project(
-                    project_id, start_date=start_date, end_date=end_date, project_index=project_index
-                )
-                df_list.append(tmp_df)
-
-        df = pandas.concat(df_list)
-        return df
-
-    def main(
-        self,
-        project_id_list: List[str],
-        start_date: str,
-        end_date: str,
-        format_target: FormatTarget,
-        output: Optional[Path] = None,
-        user_id_list: Optional[List[str]] = None,
-        parallelism: Optional[int] = None,
-    ):
-
-        df_intermediate = self.create_intermediate_df(
-            project_id_list, start_date=start_date, end_date=end_date, parallelism=parallelism
-        )
-
-        df_intermediate = filter_df_intermediate(df_intermediate, user_id_list=user_id_list)
-        df_output = create_df_from_intermediate(df_intermediate, format_target=format_target)
-        if len(df_output) > 0:
-            print_csv(df_output, str(output) if output is not None else None)
-        else:
-            logger.warning(f"出力するデータの件数が0件なので、出力しません。")
-
-
-class ListLaborWorktime(AbstractCommandLineInterface):
-    """
-    労務管理画面の作業時間を出力する
-    """
-
-    @staticmethod
-    def validate(args: argparse.Namespace) -> bool:
-        COMMON_MESSAGE = "annofabcli experimental list_labor_worktime: error:"
-        if args.start_date is not None and args.end_date is not None:
-            if args.start_date > args.end_date:
-                print(
-                    f"{COMMON_MESSAGE} argument `START_DATE <= END_DATE` の関係を満たしていません。",
-                    file=sys.stderr,
-                )
-                return False
-
-        return True
-
-    def main(self):
-        args = self.args
-        if not self.validate(args):
-            sys.exit(COMMAND_LINE_ERROR_STATUS_CODE)
-
-        format_target = FormatTarget(args.format)
-
-        project_id_list = get_list_from_args(args.project_id)
-        user_id_list = get_list_from_args(args.user_id) if args.user_id is not None else None
-
-        main_obj = ListLaborWorktimeMain(self.service)
-        main_obj.main(
-            project_id_list,
-            start_date=args.start_date,
-            end_date=args.end_date,
-            format_target=format_target,
-            user_id_list=user_id_list,
-            output=args.output,
-            parallelism=args.parallelism,
-        )
-
-
-def main(args):
-    service = build_annofabapi_resource_and_login(args)
-    facade = AnnofabApiFacade(service)
-    ListLaborWorktime(service, facade, args).main()
-
-
-FORMAT_HELP_MESSAGE = (
-    "出力する際のフォーマットを指定してください。\n"
-    "・details: 日毎/人毎の詳細な作業時間を出力します。\n"
-    "・total_by_user:人毎の作業時間を出力します。\n"
-    "・total_by_project:プロジェクト毎の作業時間を出力します。\n"
-    "・total: 作業時間の合計値を出力します。\n"
-    "・column_list:列固定で詳細な値を出力します。\n"
-    "・column_list_per_project: 列固定で、日、メンバ、AnnoFabプロジェクトごとの作業時間を出力します。\n"
-    "・intermediate: `annofabcli experimental list_labor_worktime_from_csv`コマンドに渡せる中間ファイルを出力します。\n"
-)
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    argument_parser = ArgumentParser(parser)
-
-    parser.add_argument(
-        "-p",
-        "--project_id",
-        type=str,
-        required=True,
-        nargs="+",
-        help="集計対象のプロジェクトのproject_idを指定します。複数指定した場合は合計値を出力します。\n"
-        " ``file://`` を先頭に付けると、project_idの一覧が記載されたファイルを指定できます。",
-    )
-    parser.add_argument("--start_date", type=str, required=True, help="集計開始日(YYYY-mm-dd)")
-    parser.add_argument("--end_date", type=str, required=True, help="集計終了日(YYYY-mm-dd)")
-
-    format_choices = [e.value for e in FormatTarget]
-    parser.add_argument(
-        "-f", "--format", type=str, choices=format_choices, default="intermediate", help=FORMAT_HELP_MESSAGE
-    )
-
-    parser.add_argument(
-        "-u",
-        "--user_id",
-        type=str,
-        nargs="+",
-        required=False,
-        help="集計対象のユーザのuser_idを指定します。\n" " ``file://`` を先頭に付けると、user_idの一覧が記載されたファイルを指定できます。",
-    )
-    argument_parser.add_output(required=False)
-
-    parser.add_argument("--parallelism", type=int, required=False, help="並列度。指定しない場合は、逐次的に処理します。")
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def add_parser(subparsers: argparse._SubParsersAction):
-    subcommand_name = "list_labor_worktime"
-    subcommand_help = "労務管理画面の作業時間を出力します。"
-    description = "作業者ごとに、「作業者が入力した実績時間」と「AnnoFabが集計した作業時間」の差分を出力します。"
-
-    parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
-    parse_args(parser)
diff --git a/annofabcli/experimental/list_labor_worktime_from_csv.py b/annofabcli/experimental/list_labor_worktime_from_csv.py
deleted file mode 100644
index b5cd866c..00000000
--- a/annofabcli/experimental/list_labor_worktime_from_csv.py
+++ /dev/null
@@ -1,109 +0,0 @@
-import argparse
-import logging
-from pathlib import Path
-from typing import List, Optional
-
-import pandas
-
-import annofabcli
-import annofabcli.common.cli
-from annofabcli.common.cli import AbstractCommandLineWithoutWebapiInterface, ArgumentParser, get_list_from_args
-from annofabcli.common.utils import print_csv
-from annofabcli.experimental.list_labor_worktime import (
-    FORMAT_HELP_MESSAGE,
-    FormatTarget,
-    create_df_from_intermediate,
-    filter_df_intermediate,
-)
-
-logger = logging.getLogger(__name__)
-
-
-def list_labor_worktime_from_csv(
-    csv: Path,
-    format_target: FormatTarget,
-    *,
-    project_id_list: Optional[List[str]] = None,
-    user_id_list: Optional[List[str]] = None,
-    start_date: Optional[str] = None,
-    end_date: Optional[str] = None,
-    output: Optional[Path] = None,
-):
-    df_intermediate = pandas.read_csv(str(csv))
-    df_intermediate = filter_df_intermediate(
-        df_intermediate,
-        project_id_list=project_id_list,
-        user_id_list=user_id_list,
-        start_date=start_date,
-        end_date=end_date,
-    )
-
-    df_output = create_df_from_intermediate(df_intermediate, format_target=format_target)
-    if len(df_output) > 0:
-        print_csv(df_output, str(output) if output is not None else None)
-    else:
-        logger.warning(f"出力するデータの件数が0件なので、出力しません。")
-
-
-class ListLaborWorktimeFormCsv(AbstractCommandLineWithoutWebapiInterface):
-    def main(self):
-        args = self.args
-
-        project_id_list = get_list_from_args(args.project_id) if args.project_id is not None else None
-        user_id_list = get_list_from_args(args.user_id) if args.user_id is not None else None
-
-        list_labor_worktime_from_csv(
-            csv=args.csv,
-            format_target=FormatTarget(args.format),
-            project_id_list=project_id_list,
-            user_id_list=user_id_list,
-            start_date=args.start_date,
-            end_date=args.end_date,
-            output=args.output,
-        )
-
-
-def main(args):
-    ListLaborWorktimeFormCsv(args).main()
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    argument_parser = ArgumentParser(parser)
-    parser.add_argument(
-        "--csv", type=Path, help="'annofabcli experimental list_labor_worktime --format intermediate'の出力結果であるCSV"
-    )
-
-    parser.add_argument(
-        "-p",
-        "--project_id",
-        type=str,
-        nargs="+",
-        help="集計対象のプロジェクトのproject_idを指定します。\n" "`file://`を先頭に付けると、project_idの一覧が記載されたファイルを指定できます。",
-    )
-    parser.add_argument(
-        "-u",
-        "--user_id",
-        type=str,
-        nargs="+",
-        help="集計対象のユーザのuser_idを指定します。\n" "`file://`を先頭に付けると、user_idの一覧が記載されたファイルを指定できます。",
-    )
-    parser.add_argument("--start_date", type=str, help="集計開始日(YYYY-mm-dd)")
-    parser.add_argument("--end_date", type=str, help="集計終了日(YYYY-mm-dd)")
-
-    format_choices = [e.value for e in FormatTarget]
-    parser.add_argument(
-        "-f", "--format", type=str, choices=format_choices, default="intermediate", help=FORMAT_HELP_MESSAGE
-    )
-
-    argument_parser.add_output(required=False)
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def add_parser(subparsers: argparse._SubParsersAction):
-    subcommand_name = "list_labor_worktime_from_csv"
-    subcommand_help = "'annofabcli experimental list_labor_worktime --format intermediate'で出力したCSVを整形します。"
-    description = "'annofabcli experimental list_labor_worktime --format intermediate'で出力したCSVを整形します。"
-
-    parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
-    parse_args(parser)
diff --git a/annofabcli/experimental/subcommand_experimental.py b/annofabcli/experimental/subcommand_experimental.py
index 26863b8e..a568affc 100644
--- a/annofabcli/experimental/subcommand_experimental.py
+++ b/annofabcli/experimental/subcommand_experimental.py
@@ -4,9 +4,6 @@
 import annofabcli
 import annofabcli.common.cli
 from annofabcli.experimental import (
-    dashboard,
-    list_labor_worktime,
-    list_labor_worktime_from_csv,
     list_out_of_range_annotation_for_movie,
 )
 
@@ -15,9 +12,6 @@ def parse_args(parser: argparse.ArgumentParser):
     subparsers = parser.add_subparsers(dest="subcommand_name")
 
     # サブコマンドの定義
-    dashboard.add_parser(subparsers)
-    list_labor_worktime.add_parser(subparsers)
-    list_labor_worktime_from_csv.add_parser(subparsers)
     list_out_of_range_annotation_for_movie.add_parser(subparsers)
 
 
diff --git a/annofabcli/input_data/list_input_data.py b/annofabcli/input_data/list_input_data.py
index 24b4031b..cdf9714a 100644
--- a/annofabcli/input_data/list_input_data.py
+++ b/annofabcli/input_data/list_input_data.py
@@ -39,11 +39,6 @@ def _find_task_id_list(task_list: List[Task], input_data_id: str) -> List[str]:
                 task_id_list.append(task["task_id"])
         return task_id_list
 
-    @annofabcli.utils.allow_404_error
-    def get_input_data(self, project_id: str, input_data_id: str) -> InputData:
-        input_data, _ = self.service.api.get_input_data(project_id, input_data_id)
-        return input_data
-
     def get_input_data_from_input_data_id(self, project_id: str, input_data_id_list: List[str]) -> List[InputData]:
         input_data_list = []
         logger.debug(f"{len(input_data_id_list)}件の入力データを取得します。")
@@ -51,7 +46,7 @@ def get_input_data_from_input_data_id(self, project_id: str, input_data_id_list:
             if (index + 1) % 100 == 0:
                 logger.debug(f"{index+1} 件目の入力データを取得します。")
 
-            input_data = self.get_input_data(project_id, input_data_id)
+            input_data = self.service.wrapper.get_input_data_or_none(project_id, input_data_id)
             if input_data is not None:
                 input_data_list.append(input_data)
             else:
diff --git a/annofabcli/job/list_last_job.py b/annofabcli/job/list_last_job.py
index e28088b5..4d7ae7a0 100644
--- a/annofabcli/job/list_last_job.py
+++ b/annofabcli/job/list_last_job.py
@@ -56,17 +56,12 @@ def get_project_info(self, project_id: str, project: Project, add_details: bool
 
         return project_info
 
-    @annofabcli.utils.allow_404_error
-    def get_project(self, project_id: str) -> Project:
-        project, _ = self.service.api.get_project(project_id)
-        return project
-
     def get_last_job_list(
         self, project_id_list: List[str], job_type: ProjectJobType, add_details: bool = False
     ) -> List[ProjectJobInfo]:
         job_list = []
         for project_id in project_id_list:
-            project = self.get_project(project_id)
+            project = self.service.wrapper.get_project_or_none(project_id)
 
             if project is None:
                 logger.warning(f"project_id='{project_id}' のプロジェクトは存在しませんでした。")
diff --git a/annofabcli/labor/list_worktime_by_user.py b/annofabcli/labor/list_worktime_by_user.py
deleted file mode 100644
index 36a3ebdd..00000000
--- a/annofabcli/labor/list_worktime_by_user.py
+++ /dev/null
@@ -1,1217 +0,0 @@
-# pylint: disable=too-many-lines
-import argparse
-import calendar
-import datetime
-import logging
-from dataclasses import dataclass
-from pathlib import Path
-from typing import Any, Dict, List, Optional, Tuple
-
-import annofabapi
-import more_itertools
-import numpy
-import pandas
-from annofabapi.models import OrganizationMember, Project, ProjectMember
-from annofabapi.utils import allow_404_error
-from dataclasses_json import DataClassJsonMixin
-from more_itertools import first_true
-
-import annofabcli
-from annofabcli import AnnofabApiFacade
-from annofabcli.common.cli import AbstractCommandLineInterface, build_annofabapi_resource_and_login, get_list_from_args
-from annofabcli.common.utils import _catch_exception, isoduration_to_hour
-
-logger = logging.getLogger(__name__)
-
-
-def _create_required_columns(df: pandas.DataFrame, prior_columns: List[Any]) -> List[str]:
-    remained_columns = list(df.columns.difference(prior_columns))
-    all_columns = prior_columns + remained_columns
-    return all_columns
-
-
-@dataclass(frozen=True)
-class User(DataClassJsonMixin):
-    account_id: str
-    user_id: str
-    username: str
-    biography: Optional[str]
-
-
-@dataclass(frozen=True)
-class LaborWorktime(DataClassJsonMixin):
-    """
-    労務管理情報
-    """
-
-    date: str
-    organization_id: str
-    organization_name: str
-    project_id: str
-    project_title: str
-    account_id: str
-    user_id: str
-    username: str
-    biography: Optional[str]
-    worktime_plan_hour: float
-    """労務管理画面の予定作業時間"""
-    worktime_result_hour: float
-    """労務管理画面の実績作業時間"""
-    worktime_monitored_hour: Optional[float]
-    """AnnoFabの作業時間"""
-    working_description: Optional[str]
-    """実績作業時間に対する備考"""
-
-
-@dataclass(frozen=True)
-class LaborAvailability(DataClassJsonMixin):
-    """
-    労務管理情報
-    """
-
-    date: str
-    account_id: str
-    user_id: str
-    username: str
-    availability_hour: float
-
-
-@dataclass(frozen=True)
-class SumLaborWorktime(DataClassJsonMixin):
-    """
-    出力用の作業時間情報
-    """
-
-    date: str
-    user_id: str
-    worktime_plan_hour: float
-    worktime_result_hour: float
-
-
-class ListWorktimeByUserMain:
-    def __init__(self, service: annofabapi.Resource):
-        self.service = service
-        self.facade = AnnofabApiFacade(service)
-
-    DATE_FORMAT = "%Y-%m-%d"
-    MONTH_FORMAT = "%Y-%m"
-
-    _dict_account_statistics: Dict[str, List[Dict[str, Any]]] = {}
-    """project_idごとの統計情報dict"""
-
-    @allow_404_error
-    def _get_account_statistics(self, project_id) -> Optional[List[Any]]:
-        account_statistics = self.service.wrapper.get_account_statistics(project_id)
-        return account_statistics
-
-    def _get_worktime_monitored_hour_from_project_id(
-        self, project_id: str, account_id: str, date: str
-    ) -> Optional[float]:
-        account_statistics = self._dict_account_statistics.get(project_id)
-        if account_statistics is None:
-            result = self._get_account_statistics(project_id)
-            if result is not None:
-                account_statistics = result
-            else:
-                logger.warning(f"project_id={project_id}: プロジェクトにアクセスできないため、アカウント統計情報を取得できませんでした。")
-                account_statistics = []
-
-            self._dict_account_statistics[project_id] = account_statistics
-
-        return self._get_worktime_monitored_hour(account_statistics, account_id=account_id, date=date)
-
-    @staticmethod
-    def _get_worktime_monitored_hour(
-        account_statistics: List[Dict[str, Any]], account_id: str, date: str
-    ) -> Optional[float]:
-        """
-        AnnoFabの作業時間を取得する。
-        """
-        stat = first_true(account_statistics, pred=lambda e: e["account_id"] == account_id)
-        if stat is None:
-            return None
-        histories = stat["histories"]
-        hist = first_true(histories, pred=lambda e: e["date"] == date)
-        if hist is None:
-            return None
-        return isoduration_to_hour(hist["worktime"])
-
-    @staticmethod
-    def create_required_columns(df, prior_columns):
-        remained_columns = list(df.columns.difference(prior_columns))
-        all_columns = prior_columns + remained_columns
-        return all_columns
-
-    @staticmethod
-    def get_member_from_user_id(
-        organization_member_list: List[OrganizationMember], user_id: str
-    ) -> Optional[OrganizationMember]:
-        member = more_itertools.first_true(organization_member_list, pred=lambda e: e["user_id"] == user_id)
-        return member
-
-    @staticmethod
-    def get_project_title(project_list: List[Project], project_id: str) -> str:
-        project = more_itertools.first_true(project_list, pred=lambda e: e["project_id"] == project_id)
-        if project is not None:
-            return project["title"]
-        else:
-            return ""
-
-    @staticmethod
-    def get_worktime_hour(working_time_by_user: Optional[Dict[str, Any]], key: str) -> float:
-        if working_time_by_user is None:
-            return 0
-
-        value = working_time_by_user.get(key)
-        if value is None:
-            return 0
-        else:
-            return value / 3600 / 1000
-
-    @staticmethod
-    def _get_working_description(working_time_by_user: Optional[Dict[str, Any]]) -> Optional[str]:
-        if working_time_by_user is None:
-            return None
-
-        return working_time_by_user.get("description")
-
-    @staticmethod
-    def _get_labor_worktime(
-        labor: Dict[str, Any],
-        member: Optional[ProjectMember],
-        project_title: str,
-        organization_name: str,
-        worktime_monitored_hour: Optional[float],
-    ) -> LaborWorktime:
-        new_labor = LaborWorktime(
-            date=labor["date"],
-            organization_id=labor["organization_id"],
-            organization_name=organization_name,
-            project_id=labor["project_id"],
-            project_title=project_title,
-            account_id=labor["account_id"],
-            user_id=member["user_id"] if member is not None else labor["account_id"],
-            username=member["username"] if member is not None else labor["account_id"],
-            biography=member["biography"] if member is not None else None,
-            worktime_plan_hour=labor["plan_worktime"] if labor["plan_worktime"] is not None else 0,
-            worktime_result_hour=labor["actual_worktime"] if labor["actual_worktime"] is not None else 0,
-            working_description=labor["working_description"],
-            worktime_monitored_hour=worktime_monitored_hour,
-        )
-        return new_labor
-
-    def get_labor_availability_list_dict(
-        self,
-        user_list: List[User],
-        start_date: str,
-        end_date: str,
-    ) -> Dict[str, List[LaborAvailability]]:
-        """
-        予定稼働時間を取得する
-        Args:
-            user_list:
-            start_date:
-            end_date:
-
-        Returns:
-
-        """
-        labor_availability_dict = {}
-        for user in user_list:
-            # 予定稼働時間を取得するには、特殊な組織IDを渡す
-            labor_list = self.service.wrapper.get_labor_control_availability(
-                from_date=start_date,
-                to_date=end_date,
-                account_id=user.account_id,
-            )
-            new_labor_list = []
-            for labor in labor_list:
-                new_labor = LaborAvailability(
-                    date=labor["date"],
-                    account_id=labor["account_id"],
-                    user_id=user.user_id,
-                    username=user.username,
-                    availability_hour=labor["availability"] if labor["availability"] is not None else 0,
-                )
-                new_labor_list.append(new_labor)
-            labor_availability_dict[user.user_id] = new_labor_list
-        return labor_availability_dict
-
-    def get_labor_list_from_project_id(
-        self,
-        project_id: str,
-        account_id_list: Optional[List[str]],
-        start_date: Optional[str],
-        end_date: Optional[str],
-        add_monitored_worktime: bool = False,
-    ) -> List[LaborWorktime]:
-        organization, _ = self.service.api.get_organization_of_project(project_id)
-        organization_name = organization["organization_name"]
-
-        if account_id_list is None:
-            logger.debug(f"project_id={project_id}の、すべての労務管理情報を取得しています。")
-            labor_list = self.service.wrapper.get_labor_control_worktime(
-                project_id=project_id,
-                organization_id=organization["organization_id"],
-                from_date=start_date,
-                to_date=end_date,
-            )
-        else:
-            labor_list = []
-            for account_id in account_id_list:
-                logger.debug(f"project_id={project_id}の、ユーザ{len(account_id_list)}件分の労務管理情報を取得しています。")
-                tmp_labor_list = self.service.wrapper.get_labor_control_worktime(
-                    project_id=project_id, from_date=start_date, to_date=end_date, account_id=account_id
-                )
-                labor_list.extend(tmp_labor_list)
-
-        project_title = self.service.api.get_project(project_id)[0]["title"]
-        labor_list = [
-            e
-            for e in labor_list
-            if (e["actual_worktime"] is not None and e["actual_worktime"] > 0)
-            or (e["plan_worktime"] is not None and e["plan_worktime"] > 0)
-        ]
-        logger.info(f"'{project_title}'プロジェクト('{project_id}')の労務管理情報の件数: {len(labor_list)}")
-
-        new_labor_list = []
-        for labor in labor_list:
-            # 個人に紐付かないデータの場合
-            if labor["account_id"] is None:
-                continue
-
-            member = self.facade.get_project_member_from_account_id(labor["project_id"], labor["account_id"])
-            if add_monitored_worktime:
-                try:
-                    worktime_monitored_hour = self._get_worktime_monitored_hour_from_project_id(
-                        project_id=project_id, account_id=labor["account_id"], date=labor["date"]
-                    )
-                except Exception:  # pylint: disable=broad-except
-                    logger.warning(f"project_id={project_id}: 計測作業時間を取得できませんでした。", exc_info=True)
-                    worktime_monitored_hour = None
-            else:
-                worktime_monitored_hour = None
-
-            new_labor = self._get_labor_worktime(
-                labor,
-                member=member,
-                project_title=project_title,
-                organization_name=organization_name,
-                worktime_monitored_hour=worktime_monitored_hour,
-            )
-            new_labor_list.append(new_labor)
-
-        return new_labor_list
-
-    def get_labor_list_from_organization_name(
-        self,
-        organization_name: str,
-        account_id_list: Optional[List[str]],
-        start_date: Optional[str],
-        end_date: Optional[str],
-        add_monitored_worktime: bool = False,
-    ) -> List[LaborWorktime]:
-        organization, _ = self.service.api.get_organization(organization_name)
-        organization_id = organization["organization_id"]
-
-        if account_id_list is None:
-            logger.debug(f"organization_name={organization_name}の、すべての労務管理情報を取得しています。")
-            labor_list = self.service.wrapper.get_labor_control_worktime(
-                organization_id=organization_id, from_date=start_date, to_date=end_date
-            )
-        else:
-            labor_list = []
-            logger.debug(f"organization_name={organization_name}の、ユーザ{len(account_id_list)}件分の労務管理情報を取得しています。")
-            for account_id in account_id_list:
-                tmp_labor_list = self.service.wrapper.get_labor_control_worktime(
-                    organization_id=organization_id, from_date=start_date, to_date=end_date, account_id=account_id
-                )
-                labor_list.extend(tmp_labor_list)
-
-        labor_list = [
-            e
-            for e in labor_list
-            if (e["actual_worktime"] is not None and e["actual_worktime"] > 0)
-            or (e["plan_worktime"] is not None and e["plan_worktime"] > 0)
-        ]
-
-        logger.info(f"'{organization_name}'組織の労務管理情報の件数: {len(labor_list)}")
-        project_list = self.service.wrapper.get_all_projects_of_organization(organization_name)
-
-        new_labor_list = []
-        for labor in labor_list:
-            try:
-                member = self.facade.get_project_member_from_account_id(labor["project_id"], labor["account_id"])
-            except Exception:  # pylint: disable=broad-except
-                logger.warning(f"project_id={labor['project_id']}: メンバ一覧を取得できませんでした。", exc_info=True)
-                member = None
-
-            project_title = self.get_project_title(project_list, labor["project_id"])
-            if add_monitored_worktime:
-                try:
-                    worktime_monitored_hour = self._get_worktime_monitored_hour_from_project_id(
-                        project_id=labor["project_id"], account_id=labor["account_id"], date=labor["date"]
-                    )
-                except Exception:  # pylint: disable=broad-except
-                    logger.warning(f"project_id={labor['project_id']}: 計測作業時間を取得できませんでした。", exc_info=True)
-                    worktime_monitored_hour = None
-            else:
-                worktime_monitored_hour = None
-
-            new_labor = self._get_labor_worktime(
-                labor,
-                member=member,
-                project_title=project_title,
-                organization_name=organization_name,
-                worktime_monitored_hour=worktime_monitored_hour,
-            )
-            new_labor_list.append(new_labor)
-
-        return new_labor_list
-
-    @staticmethod
-    def get_sum_worktime_list(
-        labor_list: List[LaborWorktime], user_id: str, start_date: str, end_date: str
-    ) -> List[SumLaborWorktime]:
-        sum_labor_list = []
-        for date in pandas.date_range(start=start_date, end=end_date):
-            str_date = date.strftime(ListWorktimeByUserMain.DATE_FORMAT)
-            filtered_list = [e for e in labor_list if e.user_id == user_id and e.date == str_date]
-            worktime_plan_hour = sum([e.worktime_plan_hour for e in filtered_list])
-            worktime_result_hour = sum([e.worktime_result_hour for e in filtered_list])
-
-            labor = SumLaborWorktime(
-                user_id=user_id,
-                date=date,
-                worktime_plan_hour=worktime_plan_hour,
-                worktime_result_hour=worktime_result_hour,
-            )
-            sum_labor_list.append(labor)
-
-        return sum_labor_list
-
-    @staticmethod
-    @_catch_exception
-    def write_sum_worktime_list(sum_worktime_df: pandas.DataFrame, output_dir: Path):
-        sum_worktime_df.round(3).to_csv(str(output_dir / "ユーザごとの作業時間.csv"), encoding="utf_8_sig", index=False)
-
-    @staticmethod
-    @_catch_exception
-    def write_sum_plan_worktime_list(sum_worktime_df: pandas.DataFrame, output_dir: Path) -> None:
-        """
-        出勤予定かどうかを判断するため、作業予定時間が"0"のときは"☓",　そうでないときは"○"で出力する
-        Args:
-            sum_worktime_df:
-            output_dir:
-
-        """
-
-        def create_mark(value) -> str:
-            if value == 0:
-                return "×"
-            else:
-                return "○"
-
-        def is_plan_column(c) -> bool:
-            c1, c2 = c
-            if c1 in ["date", "dayofweek"]:
-                return False
-            return c2 == "作業予定"
-
-        username_list = [e[0] for e in sum_worktime_df.columns if is_plan_column(e)]
-
-        for username in username_list:
-            # SettingWithCopyWarning を避けるため、暫定的に値をコピーする
-            sum_worktime_df[(username, "作業予定_記号")] = sum_worktime_df[(username, "作業予定")].map(create_mark)
-
-        output_columns = [("date", ""), ("dayofweek", "")] + [(e, "作業予定_記号") for e in username_list]
-        sum_worktime_df[output_columns].to_csv(str(output_dir / "ユーザごとの作業予定_記号.csv"), encoding="utf_8_sig", index=False)
-
-    @staticmethod
-    @_catch_exception
-    def write_worktime_list(worktime_df: pandas.DataFrame, output_dir: Path, add_monitored_worktime: bool = False):
-        worktime_df = worktime_df.rename(
-            columns={
-                "worktime_plan_hour": "作業予定時間",
-                "worktime_result_hour": "作業実績時間",
-                "worktime_monitored_hour": "計測時間",
-                "working_description": "備考",
-            }
-        )
-        columns = [
-            "date",
-            "organization_name",
-            "project_title",
-            "project_id",
-            "username",
-            "biography",
-            "user_id",
-            "作業予定時間",
-            "作業実績時間",
-            "計測時間",
-            "備考",
-        ]
-        if not add_monitored_worktime:
-            columns.remove("計測時間")
-
-        worktime_df[columns].round(3).to_csv(str(output_dir / "作業時間の詳細一覧.csv"), encoding="utf_8_sig", index=False)
-
-    @staticmethod
-    @_catch_exception
-    def write_worktime_per_user_date(worktime_df_per_date_user: pandas.DataFrame, output_dir: Path):
-        add_availability = "availability_hour" in worktime_df_per_date_user.columns
-        target_renamed_columns = {"worktime_plan_hour": "作業予定時間", "worktime_result_hour": "作業実績時間"}
-        if add_availability:
-            target_renamed_columns.update({"availability_hour": "予定稼働時間"})
-
-        df = worktime_df_per_date_user.rename(columns=target_renamed_columns)
-        columns = [
-            "date",
-            "user_id",
-            "username",
-            "biography",
-            "予定稼働時間",
-            "作業予定時間",
-            "作業実績時間",
-        ]
-        if not add_availability:
-            columns.remove("予定稼働時間")
-
-        df[columns].round(3).to_csv(str(output_dir / "日ごとの作業時間の一覧.csv"), encoding="utf_8_sig", index=False)
-
-    @staticmethod
-    @_catch_exception
-    def write_worktime_per_user(worktime_df_per_user: pandas.DataFrame, output_dir: Path, add_availability: bool):
-        target_renamed_columns = {
-            "worktime_plan_hour": "作業予定時間",
-            "worktime_result_hour": "作業実績時間",
-            "result_working_days": "実績稼働日数",
-        }
-        if add_availability:
-            target_renamed_columns.update({"availability_hour": "予定稼働時間"})
-            target_renamed_columns.update({"availability_days": "予定稼働日数"})
-
-        df = worktime_df_per_user.rename(columns=target_renamed_columns)
-        columns = [
-            "user_id",
-            "username",
-            "biography",
-            "予定稼働時間",
-            "作業予定時間",
-            "作業実績時間",
-            "予定稼働日数",
-            "実績稼働日数",
-        ]
-        if not add_availability:
-            columns.remove("予定稼働時間")
-            columns.remove("予定稼働日数")
-
-        df[columns].round(3).to_csv(str(output_dir / "summary.csv"), encoding="utf_8_sig", index=False)
-
-    def get_organization_member_list(
-        self, organization_name_list: Optional[List[str]], project_id_list: Optional[List[str]]
-    ) -> List[OrganizationMember]:
-        member_list: List[OrganizationMember] = []
-
-        if project_id_list is not None:
-            tmp_organization_name_list = []
-            for project_id in project_id_list:
-                organization, _ = self.service.api.get_organization_of_project(project_id)
-                tmp_organization_name_list.append(organization["organization_name"])
-
-            organization_name_list = list(set(tmp_organization_name_list))
-
-        if organization_name_list is not None:
-            for organization_name in organization_name_list:
-                member_list.extend(self.service.wrapper.get_all_organization_members(organization_name))
-
-        return member_list
-
-    def _get_user_from_organization_name_list(self, organization_name_list: List[str], user_id: str) -> Optional[User]:
-        for organization_name in organization_name_list:
-            organization_member = self.service.wrapper.get_organization_member_or_none(organization_name, user_id)
-            if organization_member is not None:
-                return User(
-                    user_id=organization_member["user_id"],
-                    account_id=organization_member["account_id"],
-                    username=organization_member["username"],
-                    biography=organization_member["biography"],
-                )
-        return None
-
-    def _get_user_from_project_id_list(self, project_id_list: List[str], user_id: str) -> Optional[User]:
-        for project_id in project_id_list:
-            project_member = self.service.wrapper.get_project_member_or_none(project_id, user_id)
-            if project_member is not None:
-                return User(
-                    user_id=project_member["user_id"],
-                    account_id=project_member["account_id"],
-                    username=project_member["username"],
-                    biography=project_member["biography"],
-                )
-        return None
-
-    def get_user_list(
-        self,
-        labor_list: List[LaborWorktime],
-        organization_name_list: Optional[List[str]] = None,
-        project_id_list: Optional[List[str]] = None,
-        user_id_list: Optional[List[str]] = None,
-    ) -> List[User]:
-        """
-        summary.csvに出力するユーザ一覧を取得する。
-
-        Args:
-            labor_list:
-            organization_name_list:
-            project_id_list:
-            user_id_list:
-
-        Returns:
-            ユーザ一覧
-
-        """
-        df = (
-            pandas.DataFrame(labor_list, columns=["account_id", "user_id", "username", "biography"])
-            .drop_duplicates()
-            .set_index("user_id")
-        )
-
-        user_list: List[User] = []
-
-        if user_id_list is None:
-            for user_id, row in df.iterrows():
-                user_list.append(
-                    User(
-                        user_id=str(user_id),
-                        account_id=row["account_id"],
-                        username=row["username"],
-                        biography=row["biography"],
-                    )
-                )
-            return user_list
-
-        if organization_name_list is not None:
-            for user_id in user_id_list:
-                if user_id in df.index:
-                    row = df.loc[user_id]
-                    user_list.append(
-                        User(
-                            user_id=str(user_id),
-                            account_id=row["account_id"],
-                            username=row["username"],
-                            biography=row["biography"],
-                        )
-                    )
-                    continue
-
-                user = self._get_user_from_organization_name_list(organization_name_list, user_id)
-                if user is not None:
-                    user_list.append(user)
-                else:
-                    logger.warning(f"user_id={user_id} のユーザは、組織メンバに存在しませんでした。")
-
-        if project_id_list is not None:
-            for user_id in user_id_list:
-                if user_id in df.index:
-                    row = df.loc[user_id]
-                    user_list.append(
-                        User(
-                            user_id=str(user_id),
-                            account_id=row["account_id"],
-                            username=row["username"],
-                            biography=row["biography"],
-                        )
-                    )
-                    continue
-
-                user = self._get_user_from_project_id_list(project_id_list, user_id)
-                if user is not None:
-                    user_list.append(user)
-                else:
-                    logger.warning(f"user_id={user_id} のユーザは、プロジェクトメンバに存在しませんでした。")
-
-        return user_list
-
-    @staticmethod
-    def get_availability_list(
-        labor_availability_list: List[LaborAvailability],
-        start_date: str,
-        end_date: str,
-    ) -> List[Optional[float]]:
-        def get_availability_hour(str_date: str) -> Optional[float]:
-            labor = more_itertools.first_true(labor_availability_list, pred=lambda e: e.date == str_date)
-            if labor is not None:
-                return labor.availability_hour
-            else:
-                return None
-
-        availability_list: List[Optional[float]] = []
-        for date in pandas.date_range(start=start_date, end=end_date):
-            str_date = date.strftime(ListWorktimeByUserMain.DATE_FORMAT)
-            availability_list.append(get_availability_hour(str_date))
-
-        return availability_list
-
-    def get_account_id_list_from_project_id(self, user_id_list: List[str], project_id_list: List[str]) -> List[str]:
-        """
-        project_idのリストから、対象ユーザのaccount_id を取得する。
-
-        Args:
-            user_id_list:
-            organization_name_list:
-
-        Returns:
-            account_idのリスト
-        """
-        account_id_list = []
-        not_exists_user_id_list = []
-        for user_id in user_id_list:
-            member_exists = False
-            for project_id in project_id_list:
-                member = self.facade.get_project_member_from_user_id(project_id, user_id)
-                if member is not None:
-                    account_id_list.append(member["account_id"])
-                    member_exists = True
-                    break
-            if not member_exists:
-                not_exists_user_id_list.append(user_id)
-
-        if len(not_exists_user_id_list) == 0:
-            return account_id_list
-        else:
-            raise ValueError(f"以下のユーザは、指定されたプロジェクトのプロジェクトメンバではありませんでした。\n{not_exists_user_id_list}")
-
-    def get_account_id_list_from_organization_name(
-        self, user_id_list: List[str], organization_name_list: List[str]
-    ) -> List[str]:
-        """
-        組織名のリストから、対象ユーザのaccount_id を取得する。
-
-        Args:
-            user_id_list:
-            organization_name_list:
-
-        Returns:
-            account_idのリスト
-        """
-
-        def _get_account_id(fuser_id: str) -> Optional[str]:
-            # 脱退した可能性のあるユーザの組織メンバ情報を取得する
-            for organization_name in organization_name_list:
-                member = self.service.wrapper.get_organization_member_or_none(organization_name, fuser_id)
-                if member is not None:
-                    return member["account_id"]
-            return None
-
-        # 組織メンバの一覧をする（ただし脱退したメンバは取得できない）
-        all_organization_member_list = []
-        for organization_name in organization_name_list:
-            all_organization_member_list.extend(self.service.wrapper.get_all_organization_members(organization_name))
-
-        user_id_dict = {e["user_id"]: e["account_id"] for e in all_organization_member_list}
-        account_id_list = []
-        not_exists_user_id_list = []
-        for user_id in user_id_list:
-            if user_id in user_id_dict:
-                account_id_list.append(user_id_dict[user_id])
-            else:
-                account_id = _get_account_id(user_id)
-                if account_id is not None:
-                    account_id_list.append(account_id)
-                else:
-                    not_exists_user_id_list.append(user_id)
-
-        if len(not_exists_user_id_list) == 0:
-            return account_id_list
-        else:
-            raise ValueError(f"以下のユーザは、指定された組織の組織メンバではありませんでした。\n{not_exists_user_id_list}")
-
-    def get_labor_list(
-        self,
-        organization_name_list: Optional[List[str]],
-        project_id_list: Optional[List[str]],
-        user_id_list: Optional[List[str]],
-        start_date: Optional[str],
-        end_date: Optional[str],
-        add_monitored_worktime: bool = False,
-    ) -> List[LaborWorktime]:
-
-        labor_list: List[LaborWorktime] = []
-        account_id_list: Optional[List[str]] = None
-
-        logger.info(f"労務管理情報を取得します。")
-        if project_id_list is not None:
-            if user_id_list is not None:
-                account_id_list = self.get_account_id_list_from_project_id(
-                    user_id_list, project_id_list=project_id_list
-                )
-
-            for project_id in project_id_list:
-                labor_list.extend(
-                    self.get_labor_list_from_project_id(
-                        project_id,
-                        account_id_list=account_id_list,
-                        start_date=start_date,
-                        end_date=end_date,
-                        add_monitored_worktime=add_monitored_worktime,
-                    )
-                )
-
-        elif organization_name_list is not None:
-            if user_id_list is not None:
-                account_id_list = self.get_account_id_list_from_organization_name(
-                    user_id_list, organization_name_list=organization_name_list
-                )
-            for organization_name in organization_name_list:
-                labor_list.extend(
-                    self.get_labor_list_from_organization_name(
-                        organization_name,
-                        account_id_list=account_id_list,
-                        start_date=start_date,
-                        end_date=end_date,
-                        add_monitored_worktime=add_monitored_worktime,
-                    )
-                )
-
-        else:
-            raise RuntimeError(f"organization_name_list or project_id_list を指定してください。")
-
-        # 集計対象ユーザで絞り込む
-        if user_id_list is not None:
-            return [e for e in labor_list if e.user_id in user_id_list]
-        else:
-            return labor_list
-
-    @staticmethod
-    def create_sum_worktime_df(
-        labor_list: List[LaborWorktime],
-        user_list: List[User],
-        start_date: str,
-        end_date: str,
-        labor_availability_list_dict: Optional[Dict[str, List[LaborAvailability]]] = None,
-    ):
-        reform_dict = {
-            ("date", ""): [
-                e.strftime(ListWorktimeByUserMain.DATE_FORMAT)
-                for e in pandas.date_range(start=start_date, end=end_date)
-            ],
-            ("dayofweek", ""): [e.strftime("%a") for e in pandas.date_range(start=start_date, end=end_date)],
-        }
-
-        username_list = []
-        for user in user_list:
-            sum_worktime_list = ListWorktimeByUserMain.get_sum_worktime_list(
-                labor_list, user_id=user.user_id, start_date=start_date, end_date=end_date
-            )
-
-            username_list.append(user.username)
-            reform_dict.update(
-                {
-                    (user.username, "作業予定"): [e.worktime_plan_hour for e in sum_worktime_list],
-                    (user.username, "作業実績"): [e.worktime_result_hour for e in sum_worktime_list],
-                }
-            )
-
-            if labor_availability_list_dict is not None:
-                labor_availability_list = labor_availability_list_dict.get(user.user_id, [])
-                reform_dict.update(
-                    {
-                        (user.username, "予定稼働"): ListWorktimeByUserMain.get_availability_list(
-                            labor_availability_list, start_date, end_date
-                        )
-                    }
-                )
-
-        key_list = ["作業予定", "作業実績", "予定稼働"] if labor_availability_list_dict else ["作業予定", "作業実績"]
-        for key in key_list:
-            data = numpy.array([reform_dict[(username, key)] for username in username_list], dtype=float)
-            data = numpy.nan_to_num(data)
-            reform_dict[("合計", key)] = list(numpy.sum(data, axis=0))  # type: ignore
-
-        columns = (
-            [("date", ""), ("dayofweek", "")]
-            + [("合計", key) for key in key_list]
-            + [(username, key) for username in username_list for key in key_list]
-        )
-
-        sum_worktime_df = pandas.DataFrame(reform_dict, columns=columns)
-        return sum_worktime_df
-
-    @staticmethod
-    def create_worktime_df_per_date_user(
-        worktime_df: pandas.DataFrame,
-        user_df: pandas.DataFrame,
-        labor_availability_list_dict: Optional[Dict[str, List[LaborAvailability]]] = None,
-    ) -> pandas.DataFrame:
-        value_df = (
-            worktime_df.pivot_table(
-                values=["worktime_plan_hour", "worktime_result_hour"], index=["date", "user_id"], aggfunc=numpy.sum
-            )
-            .fillna(0)
-            .reset_index()
-        )
-        if len(value_df) == 0:
-            value_df = pandas.DataFrame(columns=["date", "user_id", "worktime_plan_hour", "worktime_result_hour"])
-
-        if labor_availability_list_dict is not None:
-            all_availability_list = []
-            for availability_list in labor_availability_list_dict.values():
-                all_availability_list.extend(availability_list)
-
-            if len(all_availability_list) > 0:
-                availability_df = pandas.DataFrame([e.to_dict() for e in all_availability_list])
-            else:
-                availability_df = pandas.DataFrame(columns=["date", "user_id", "availability_hour"])
-
-            value_df = (
-                value_df.merge(
-                    availability_df[["date", "user_id", "availability_hour"]], how="outer", on=["date", "user_id"]
-                )
-                .fillna(0)
-                .reset_index()
-            )
-
-        if len(value_df) > 0:
-            return user_df.reset_index().merge(value_df, how="left", on=["user_id"]).reset_index()
-        else:
-            return pandas.DataFrame()
-
-    @staticmethod
-    def set_day_count_to_dataframe(
-        worktime_df_per_date_user: pandas.DataFrame, value_df: pandas.DataFrame, worktime_column: str, days_column: str
-    ):
-        df_filter = worktime_df_per_date_user[worktime_df_per_date_user[worktime_column] > 0]
-        if len(df_filter) > 0:
-            value_df[days_column] = (
-                df_filter.pivot_table(index=["user_id"], values="worktime_result_hour", aggfunc="count")
-                .fillna(0)
-                .astype(pandas.Int64Dtype())
-            )
-        else:
-            value_df[days_column] = 0
-
-    @staticmethod
-    def get_value_columns(columns: pandas.Series) -> pandas.Series:
-        """
-        ユーザ情報以外のcolumnsを取得する
-        """
-        return columns.drop(["user_id", "username", "biography"])
-
-    @staticmethod
-    def create_worktime_df_per_user(
-        worktime_df_per_date_user: pandas.DataFrame, user_df: pandas.DataFrame, add_availability: bool = False
-    ) -> pandas.DataFrame:
-        if len(worktime_df_per_date_user) > 0:
-            value_df = worktime_df_per_date_user.pivot_table(index=["user_id"], aggfunc=numpy.sum).fillna(0)
-            ListWorktimeByUserMain.set_day_count_to_dataframe(
-                worktime_df_per_date_user,
-                value_df,
-                worktime_column="worktime_result_hour",
-                days_column="result_working_days",
-            )
-            ListWorktimeByUserMain.set_day_count_to_dataframe(
-                worktime_df_per_date_user,
-                value_df,
-                worktime_column="worktime_plan_hour",
-                days_column="plan_working_days",
-            )
-
-            if add_availability:
-                ListWorktimeByUserMain.set_day_count_to_dataframe(
-                    worktime_df_per_date_user,
-                    value_df,
-                    worktime_column="availability_hour",
-                    days_column="availability_days",
-                )
-            value_df.fillna(0, inplace=True)
-
-        else:
-            columns = [
-                "availability_hour",
-                "worktime_plan_hour",
-                "worktime_result_hour",
-                "availability_days",
-                "plan_working_days",
-                "result_working_days",
-            ]
-            if not add_availability:
-                columns.remove("availability_hour")
-                columns.remove("availability_days")
-            value_df = pandas.DataFrame(columns=columns)
-
-        user_df.set_index("user_id", inplace=True)
-
-        df = user_df.join(value_df, how="left").reset_index()
-        value_columns = ListWorktimeByUserMain.get_value_columns(df.columns)
-        df[value_columns] = df[value_columns].fillna(0)
-        return df
-
-    def write_labor_list(
-        self,
-        labor_list: List[LaborWorktime],
-        user_list: List[User],
-        start_date: str,
-        end_date: str,
-        output_dir: Path,
-        labor_availability_list_dict: Optional[Dict[str, List[LaborAvailability]]] = None,
-        add_monitored_worktime: bool = False,
-    ):
-        if len(labor_list) > 0:
-            worktime_df = pandas.DataFrame([e.to_dict() for e in labor_list])
-            self.write_worktime_list(worktime_df, output_dir, add_monitored_worktime)
-        else:
-            worktime_df = pandas.DataFrame(columns=["date", "user_id", "worktime_plan_hour", "worktime_result_hour"])
-            logger.info("予定作業時間または実績作業時間が入力されているデータは見つからなかったので、'作業時間の詳細一覧.csv' は出力しません。")
-
-        # 日ごとの作業時間の一覧.csv を出力
-        user_df = pandas.DataFrame(user_list)
-        worktime_df_per_date_user = self.create_worktime_df_per_date_user(
-            worktime_df=worktime_df, user_df=user_df, labor_availability_list_dict=labor_availability_list_dict
-        )
-        if len(worktime_df_per_date_user) > 0:
-            self.write_worktime_per_user_date(worktime_df_per_date_user, output_dir)
-        else:
-            logger.info("日ごとの作業時間情報に関するデータが見つからなかったので、 '日ごとの作業時間の一覧.csv' は出力しません。")
-
-        add_availability = labor_availability_list_dict is not None
-        worktime_df_per_user = self.create_worktime_df_per_user(
-            worktime_df_per_date_user=worktime_df_per_date_user, user_df=user_df, add_availability=add_availability
-        )
-        self.write_worktime_per_user(worktime_df_per_user, output_dir, add_availability=add_availability)
-
-        # 行方向に日付、列方向にユーザを表示したDataFrame
-        sum_worktime_df = self.create_sum_worktime_df(
-            labor_list=labor_list,
-            user_list=user_list,
-            start_date=start_date,
-            end_date=end_date,
-            labor_availability_list_dict=labor_availability_list_dict,
-        )
-        self.write_sum_worktime_list(sum_worktime_df, output_dir)
-        self.write_sum_plan_worktime_list(sum_worktime_df, output_dir)
-
-    def main(
-        self,
-        organization_name_list: Optional[List[str]],
-        project_id_list: Optional[List[str]],
-        user_id_list: Optional[List[str]],
-        start_date: Optional[str],
-        end_date: Optional[str],
-        output_dir: Path,
-        add_availability: bool = False,
-        add_monitored_worktime: bool = False,
-    ) -> None:
-        """
-        作業時間の一覧を出力する
-        """
-        labor_list = self.get_labor_list(
-            organization_name_list=organization_name_list,
-            project_id_list=project_id_list,
-            user_id_list=user_id_list,
-            start_date=start_date,
-            end_date=end_date,
-            add_monitored_worktime=add_monitored_worktime,
-        )
-
-        if len(labor_list) == 0:
-            logger.info(f"予定/実績に関する労務管理情報が0件です。")
-            if start_date is None or end_date is None or user_id_list is None:
-                logger.info(f"後続の処理を続けることができないので終了します。")
-                return
-
-        if start_date is None or end_date is None:
-            sorted_date_list = sorted({e.date for e in labor_list if e.worktime_result_hour > 0})
-            if start_date is None:
-                start_date = sorted_date_list[0]
-            if end_date is None:
-                end_date = sorted_date_list[-1]
-
-        logger.info(f"集計期間: start_date={start_date}, end_date={end_date}")
-        user_list = self.get_user_list(
-            labor_list,
-            organization_name_list=organization_name_list,
-            project_id_list=project_id_list,
-            user_id_list=user_id_list,
-        )
-        logger.info(f"集計対象ユーザの数: {len(user_list)}")
-
-        labor_availability_list_dict: Optional[Dict[str, List[LaborAvailability]]] = None
-        if add_availability:
-            labor_availability_list_dict = self.get_labor_availability_list_dict(
-                user_list=user_list,
-                start_date=start_date,
-                end_date=end_date,
-            )
-
-        self.write_labor_list(
-            labor_list=labor_list,
-            user_list=user_list,
-            start_date=start_date,
-            end_date=end_date,
-            output_dir=output_dir,
-            labor_availability_list_dict=labor_availability_list_dict,
-            add_monitored_worktime=add_monitored_worktime,
-        )
-
-    def get_user_id_list_from_project_id_list(self, project_id_list: List[str]) -> List[str]:
-        """
-        プロジェクトメンバ一覧からuser_id_listを取得する。
-        Args:
-            project_id_list:
-
-        Returns:
-            user_id_list
-
-        """
-        member_list: List[Dict[str, Any]] = []
-        for project_id in project_id_list:
-            member_list.extend(self.service.wrapper.get_all_project_members(project_id))
-        user_id_list = [e["user_id"] for e in member_list]
-        return list(set(user_id_list))
-
-    @staticmethod
-    def get_first_and_last_date(str_month: str) -> Tuple[str, str]:
-        """
-        年月（"YYYY-MM"）から、月初と月末の日付を返す。
-
-        Args:
-            str_month: 年月（"YYYY-MM"）
-
-        Returns:
-            月初と月末の日付が格納されたタプル
-
-        """
-        dt_first_date = datetime.datetime.strptime(str_month, ListWorktimeByUserMain.MONTH_FORMAT)
-        _, days = calendar.monthrange(dt_first_date.year, dt_first_date.month)
-        dt_last_date = dt_first_date + datetime.timedelta(days=(days - 1))
-        return (
-            dt_first_date.strftime(ListWorktimeByUserMain.DATE_FORMAT),
-            dt_last_date.strftime(ListWorktimeByUserMain.DATE_FORMAT),
-        )
-
-    @staticmethod
-    def get_start_and_end_date_from_month(start_month: str, end_month: str) -> Tuple[str, str]:
-        """
-        開始月、終了月から、開始日付、終了日付を取得する。
-
-        Args:
-            start_month:
-            end_month:
-
-        Returns:
-
-
-        """
-        first_date, _ = ListWorktimeByUserMain.get_first_and_last_date(start_month)
-        _, end_date = ListWorktimeByUserMain.get_first_and_last_date(end_month)
-        return first_date, end_date
-
-
-class ListWorktimeByUser(AbstractCommandLineInterface):
-    """
-    作業時間をユーザごとに出力する。
-    """
-
-    @staticmethod
-    def get_start_and_end_date_from_args(args: argparse.Namespace) -> Tuple[Optional[str], Optional[str]]:
-        if args.start_date is not None:
-            start_date = args.start_date
-        elif args.start_month is not None:
-            start_date, _ = ListWorktimeByUserMain.get_first_and_last_date(args.start_month)
-        else:
-            start_date = None
-
-        if args.end_date is not None:
-            end_date = args.end_date
-        elif args.end_month is not None:
-            _, end_date = ListWorktimeByUserMain.get_first_and_last_date(args.end_month)
-        else:
-            end_date = None
-
-        return (start_date, end_date)
-
-    def main(self) -> None:
-        args = self.args
-
-        arg_user_id_list = get_list_from_args(args.user_id) if args.user_id is not None else None
-        project_id_list = get_list_from_args(args.project_id) if args.project_id is not None else None
-        organization_name_list = get_list_from_args(args.organization) if args.organization is not None else None
-
-        start_date, end_date = self.get_start_and_end_date_from_args(args)
-        output_dir = Path(args.output_dir)
-        output_dir.mkdir(exist_ok=True, parents=True)
-
-        main_obj = ListWorktimeByUserMain(self.service)
-        main_obj.main(
-            organization_name_list=organization_name_list,
-            project_id_list=project_id_list,
-            start_date=start_date,
-            end_date=end_date,
-            output_dir=output_dir,
-            user_id_list=arg_user_id_list,
-            add_availability=args.add_availability,
-            add_monitored_worktime=args.add_monitored_worktime,
-        )
-
-
-def main(args):
-    service = build_annofabapi_resource_and_login(args)
-    facade = AnnofabApiFacade(service)
-    ListWorktimeByUser(service, facade, args).main()
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    target_group = parser.add_mutually_exclusive_group(required=True)
-    target_group.add_argument(
-        "-org",
-        "--organization",
-        type=str,
-        nargs="+",
-        help="集計対象の組織名を指定してください。 ``file://`` を先頭に付けると、組織名の一覧が記載されたファイルを指定できます。",
-    )
-
-    target_group.add_argument(
-        "-p",
-        "--project_id",
-        type=str,
-        nargs="+",
-        help="集計対象のプロジェクトを指定してください。 ``file://`` を先頭に付けると、project_idの一覧が記載されたファイルを指定できます。",
-    )
-
-    parser.add_argument(
-        "-u",
-        "--user_id",
-        type=str,
-        nargs="+",
-        help="集計対象のユーザのuser_idを指定してください。 ``--organization`` を指定した場合は必須です。"
-        "指定しない場合は、プロジェクトメンバが指定されます。"
-        " ``file://`` を先頭に付けると、user_idの一覧が記載されたファイルを指定できます。",
-    )
-
-    parser.add_argument("--add_availability", action="store_true", help="指定した場合、'ユーザごとの作業時間.csv'に予定稼働時間も出力します。")
-    parser.add_argument(
-        "--add_monitored_worktime", action="store_true", help="指定した場合、'作業時間の詳細一覧.csv'にAnnoFab計測時間も出力します。"
-    )
-
-    start_period_group = parser.add_mutually_exclusive_group()
-    start_period_group.add_argument("--start_date", type=str, help="集計期間の開始日(YYYY-MM-DD)")
-    start_period_group.add_argument("--start_month", type=str, help="集計期間の開始月(YYYY-MM-DD)")
-
-    end_period_group = parser.add_mutually_exclusive_group()
-    end_period_group.add_argument("--end_date", type=str, help="集計期間の終了日(YYYY-MM)")
-    end_period_group.add_argument("--end_month", type=str, help="集計期間の終了月(YYYY-MM)")
-
-    parser.add_argument("-o", "--output_dir", type=str, required=True, help="出力先のディレクトリのパス")
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def add_parser(subparsers: Optional[argparse._SubParsersAction] = None):
-    subcommand_name = "list_worktime_by_user"
-    subcommand_help = "ユーザごとに作業予定時間、作業実績時間を出力します。"
-    description = "ユーザごとに作業予定時間、作業実績時間を出力します。"
-
-    parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description)
-    parse_args(parser)
-    return parser
diff --git a/annofabcli/labor/subcommand_labor.py b/annofabcli/labor/subcommand_labor.py
index b696c517..871e7a9f 100644
--- a/annofabcli/labor/subcommand_labor.py
+++ b/annofabcli/labor/subcommand_labor.py
@@ -4,7 +4,6 @@
 import annofabcli
 import annofabcli.common.cli
 import annofabcli.labor.list_worktime
-import annofabcli.labor.list_worktime_by_user
 
 
 def parse_args(parser: argparse.ArgumentParser):
@@ -13,7 +12,6 @@ def parse_args(parser: argparse.ArgumentParser):
 
     # サブコマンドの定義
     annofabcli.labor.list_worktime.add_parser(subparsers)
-    annofabcli.labor.list_worktime_by_user.add_parser(subparsers)
 
 
 def add_parser(subparsers: Optional[argparse._SubParsersAction] = None):
diff --git a/annofabcli/statistics/list_by_date_user.py b/annofabcli/statistics/list_by_date_user.py
deleted file mode 100644
index 069c4585..00000000
--- a/annofabcli/statistics/list_by_date_user.py
+++ /dev/null
@@ -1,238 +0,0 @@
-import argparse
-import json
-import logging
-from collections import defaultdict
-from pathlib import Path
-from typing import Any, Dict, List, Optional, Tuple
-
-import annofabapi
-import pandas
-from annofabapi.models import ProjectMemberRole, TaskHistory, TaskPhase
-
-import annofabcli
-import annofabcli.common.cli
-from annofabcli import AnnofabApiFacade
-from annofabcli.common.cli import AbstractCommandLineInterface, ArgumentParser, build_annofabapi_resource_and_login
-from annofabcli.common.download import DownloadingFile
-from annofabcli.common.utils import isoduration_to_hour
-
-logger = logging.getLogger(__name__)
-
-
-class ListSubmittedTaskCountMain:
-    def __init__(self, service: annofabapi.Resource):
-        self.service = service
-        self.facade = AnnofabApiFacade(service)
-
-    @staticmethod
-    def from_datetime_to_date(datetime: str) -> str:
-        return datetime[0:10]
-
-    @staticmethod
-    def to_formatted_dataframe(
-        submitted_task_count_df: pandas.DataFrame,
-        account_statistics_df: pandas.DataFrame,
-        user_df: pandas.DataFrame,
-    ):
-        df = (
-            submitted_task_count_df.merge(account_statistics_df, how="outer", on=["date", "account_id"])
-            .fillna(0)
-            .merge(user_df, how="inner", on="account_id")
-        )
-        df.sort_values(["date", "user_id"], inplace=True)
-        columns = [
-            "date",
-            "user_id",
-            "username",
-            "biography",
-            "worktime_hour",
-            "annotation_submitted_task_count",
-            "inspection_submitted_task_count",
-            "acceptance_submitted_task_count",
-            "rejected_task_count",
-        ]
-
-        return df[columns]
-
-    def get_task_history_dict(
-        self, project_id: str, task_history_json_path: Optional[Path]
-    ) -> Dict[str, List[TaskHistory]]:
-        if task_history_json_path is not None:
-            json_path = task_history_json_path
-        else:
-            cache_dir = annofabcli.utils.get_cache_dir()
-            json_path = cache_dir / f"task-history-{project_id}.json"
-            downloading_obj = DownloadingFile(self.service)
-            downloading_obj.download_task_history_json(project_id, dest_path=str(json_path))
-
-        logger.debug(f"タスク履歴全件ファイルを読み込み中。{json_path}")
-        with json_path.open(encoding="utf-8") as f:
-            task_history_dict = json.load(f)
-            return task_history_dict
-
-    def create_user_df(self, project_id: str):
-        member_list = self.facade.get_organization_members_from_project_id(project_id)
-        return pandas.DataFrame(member_list, columns=["account_id", "user_id", "username", "biography"])
-
-    @staticmethod
-    def _is_contained_daterange(target_date: str, start_date: Optional[str] = None, end_date: Optional[str] = None):
-        if start_date is not None:
-            if target_date < start_date:
-                return False
-        if end_date is not None:
-            if target_date > end_date:
-                return False
-        return True
-
-    def create_account_statistics_df(
-        self, project_id: str, start_date: Optional[str] = None, end_date: Optional[str] = None
-    ) -> pandas.DataFrame:
-        account_statistics = self.service.wrapper.get_account_statistics(project_id)
-        data_list: List[Dict[str, Any]] = []
-        for stat_by_user in account_statistics:
-            account_id = stat_by_user["account_id"]
-            histories = stat_by_user["histories"]
-            for stat in histories:
-                data = {
-                    "account_id": account_id,
-                    "worktime_hour": isoduration_to_hour(stat["worktime"]),
-                    "rejected_task_count": stat["tasks_rejected"],
-                    "date": stat["date"],
-                }
-                if not self._is_contained_daterange(data["date"], start_date=start_date, end_date=end_date):
-                    continue
-
-                if data["worktime_hour"] == 0 and data["rejected_task_count"] == 0:
-                    continue
-
-                data_list.append(data)
-
-        if len(data_list) > 0:
-            return pandas.DataFrame(data_list)
-        else:
-            return pandas.DataFrame(columns=["date", "account_id", "monitored_worktime_hour", "rejected_task_count"])
-
-    def create_submitted_task_count_df(
-        self,
-        task_history_dict: Dict[str, List[TaskHistory]],
-        start_date: Optional[str] = None,
-        end_date: Optional[str] = None,
-    ) -> pandas.DataFrame:
-        def _set_zero_if_not_exists(df: pandas.DataFrame):
-            for phase in TaskPhase:
-                col = f"{phase.value}_submitted_task_count"
-                if col not in df.columns:
-                    df[col] = 0
-
-        task_history_count_dict: Dict[Tuple[str, str, str], int] = defaultdict(int)
-        for _, task_history_list in task_history_dict.items():
-            for task_history in task_history_list:
-                if task_history["ended_datetime"] is not None and task_history["account_id"] is not None:
-                    ended_date = self.from_datetime_to_date(task_history["ended_datetime"])
-                    task_history_count_dict[(task_history["account_id"], task_history["phase"], ended_date)] += 1
-
-        data_list = []
-        for key, task_count in task_history_count_dict.items():
-            account_id, phase, date = key
-            data: Dict[str, Any] = {"date": date, "phase": phase, "account_id": account_id, "task_count": task_count}
-            if not self._is_contained_daterange(data["date"], start_date=start_date, end_date=end_date):
-                continue
-
-            data_list.append(data)
-
-        if len(data_list) == 0:
-            return pandas.DataFrame(
-                columns=[
-                    "date",
-                    "account_id",
-                    "annotation_submitted_task_count",
-                    "inspection_submitted_task_count",
-                    "acceptance_submitted_task_count",
-                ]
-            )
-
-        df = pandas.DataFrame(data_list)
-        df2 = df.pivot_table(columns="phase", values="task_count", index=["date", "account_id"]).fillna(0)
-        df2.rename(
-            columns={
-                "annotation": "annotation_submitted_task_count",
-                "inspection": "inspection_submitted_task_count",
-                "acceptance": "acceptance_submitted_task_count",
-            },
-            inplace=True,
-        )
-        _set_zero_if_not_exists(df2)
-        return df2
-
-    def create_user_statistics_by_date(
-        self,
-        project_id: str,
-        task_history_json_path: Optional[Path],
-        start_date: Optional[str] = None,
-        end_date: Optional[str] = None,
-    ) -> pandas.DataFrame:
-        task_history_dict = self.get_task_history_dict(project_id, task_history_json_path)
-
-        submitted_task_count_df = self.create_submitted_task_count_df(
-            task_history_dict=task_history_dict, start_date=start_date, end_date=end_date
-        )
-        account_statistics_df = self.create_account_statistics_df(project_id, start_date=start_date, end_date=end_date)
-        user_df = self.create_user_df(project_id)
-
-        df2 = self.to_formatted_dataframe(submitted_task_count_df, account_statistics_df, user_df)
-        return df2
-
-
-class ListSubmittedTaskCountArgs(AbstractCommandLineInterface):
-    def main(self):
-        args = self.args
-
-        project_id = args.project_id
-        super().validate_project(
-            project_id, project_member_roles=[ProjectMemberRole.OWNER, ProjectMemberRole.TRAINING_DATA_USER]
-        )
-
-        main_obj = ListSubmittedTaskCountMain(service=self.service)
-        df = main_obj.create_user_statistics_by_date(
-            project_id, args.task_history_json, start_date=args.start_date, end_date=args.end_date
-        )
-        self.print_csv(df)
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    argument_parser = ArgumentParser(parser)
-
-    argument_parser.add_project_id()
-
-    parser.add_argument(
-        "--task_history_json",
-        type=Path,
-        help="タスク履歴情報が記載されたJSONファイルのパスを指定してます。JSONファイルは ``$ annofabcli project download task_history`` コマンドで取得できます。"
-        "指定しない場合は、AnnoFabからタスク履歴全件ファイルをダウンロードします。",
-    )
-
-    parser.add_argument("--start_date", type=str, help="集計対象の開始日(YYYY-mm-dd)")
-    parser.add_argument("--end_date", type=str, help="集計対象の終了日(YYYY-mm-dd)")
-
-    argument_parser.add_csv_format()
-    argument_parser.add_output()
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def main(args):
-    service = build_annofabapi_resource_and_login(args)
-    facade = AnnofabApiFacade(service)
-    ListSubmittedTaskCountArgs(service, facade, args).main()
-
-
-def add_parser(subparsers: Optional[argparse._SubParsersAction] = None):
-    subcommand_name = "list_by_date_user"
-    subcommand_help = "タスク数や作業時間などの情報を、日ごとユーザごとに出力します。"
-    description = "タスク数や作業時間などの情報を、日ごとユーザごとに出力します。"
-    epilog = "オーナロールまたはアノテーションユーザロールを持つユーザで実行してください。"
-    parser = annofabcli.common.cli.add_parser(
-        subparsers, subcommand_name, subcommand_help, description=description, epilog=epilog
-    )
-    parse_args(parser)
-    return parser
diff --git a/annofabcli/statistics/list_cumulative_labor_time.py b/annofabcli/statistics/list_cumulative_labor_time.py
deleted file mode 100644
index 6a971812..00000000
--- a/annofabcli/statistics/list_cumulative_labor_time.py
+++ /dev/null
@@ -1,85 +0,0 @@
-import argparse
-import logging
-from typing import Any, Dict, List, Optional
-
-import pandas
-
-import annofabcli
-import annofabcli.common.cli
-from annofabcli import AnnofabApiFacade
-from annofabcli.common.cli import AbstractCommandLineInterface, ArgumentParser, build_annofabapi_resource_and_login
-from annofabcli.common.utils import isoduration_to_hour
-
-logger = logging.getLogger(__name__)
-
-
-class TaskProgress(AbstractCommandLineInterface):
-    """
-    タスクフェーズ別の累積作業時間を出力する。
-    """
-
-    def get_task_phase_statistics(self, project_id: str) -> List[Dict[str, Any]]:
-        """
-        フェーズごとの累積作業時間をCSVに出力するための dict 配列を作成する。
-
-        Args:
-            project_id:
-
-        Returns:
-            フェーズごとの累積作業時間に対応するdict配列
-
-        """
-        task_phase_statistics = self.service.wrapper.get_task_phase_statistics(project_id)
-        row_list: List[Dict[str, Any]] = []
-        for stat_by_date in task_phase_statistics:
-            date = stat_by_date["date"]
-            phase_stat_list = stat_by_date["phases"]
-            for phase_stat in phase_stat_list:
-                phase_stat["date"] = date
-                phase_stat["worktime_hour"] = isoduration_to_hour(phase_stat["worktime"])
-            row_list.extend(phase_stat_list)
-        return row_list
-
-    def list_cumulative_labor_time(self, project_id: str) -> None:
-        super().validate_project(project_id, project_member_roles=None)
-
-        phase_stat_list = self.get_task_phase_statistics(project_id)
-        if len(phase_stat_list) == 0:
-            logger.info("タスクフェーズ別の累積作業時間情報がないため出力しません。")
-            return
-
-        df = pandas.DataFrame(phase_stat_list)
-        # 出力対象の列を指定する
-        target_df = df[["date", "phase", "worktime_hour"]]
-        annofabcli.utils.print_csv(target_df, output=self.output, to_csv_kwargs=self.csv_format)
-
-    def main(self):
-        args = self.args
-
-        project_id = args.project_id
-        self.list_cumulative_labor_time(project_id)
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    argument_parser = ArgumentParser(parser)
-
-    argument_parser.add_project_id()
-    argument_parser.add_csv_format()
-    argument_parser.add_output()
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def main(args):
-    service = build_annofabapi_resource_and_login(args)
-    facade = AnnofabApiFacade(service)
-    TaskProgress(service, facade, args).main()
-
-
-def add_parser(subparsers: Optional[argparse._SubParsersAction] = None):
-    subcommand_name = "list_cumulative_labor_time"
-    subcommand_help = "日ごとタスクフェーズごとの累積作業時間を出力する。"
-    description = "日ごとタスクフェーズごとの累積作業時間をCSV形式で出力する。"
-    parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description=description)
-    parse_args(parser)
-    return parser
diff --git a/annofabcli/statistics/list_labor_time_per_user.py b/annofabcli/statistics/list_labor_time_per_user.py
deleted file mode 100644
index 18df1f88..00000000
--- a/annofabcli/statistics/list_labor_time_per_user.py
+++ /dev/null
@@ -1,101 +0,0 @@
-import argparse
-import logging
-from typing import Any, Dict, List, Optional
-
-import pandas
-
-import annofabcli
-import annofabcli.common.cli
-from annofabcli import AnnofabApiFacade
-from annofabcli.common.cli import AbstractCommandLineInterface, ArgumentParser, build_annofabapi_resource_and_login
-from annofabcli.common.utils import isoduration_to_hour
-
-logger = logging.getLogger(__name__)
-
-
-class LaborTimePerUser(AbstractCommandLineInterface):
-    """
-    メンバ別の作業時間を出力する。
-    """
-
-    def get_labor_time_per_user(self, project_id: str) -> List[Dict[str, Any]]:
-        """
-        メンバ別の作業時間をCSVに出力するための dict 配列を作成する。
-
-        Args:
-            project_id:
-
-        Returns:
-            メンバ別の作業時間をCSVに出力するための dict 配列
-
-        """
-        account_statistics = self.service.wrapper.get_account_statistics(project_id)
-        row_list: List[Dict[str, Any]] = []
-        for stat_by_user in account_statistics:
-            account_id = stat_by_user["account_id"]
-            member = self.facade.get_project_member_from_account_id(project_id, account_id)
-
-            histories = stat_by_user["histories"]
-            for stat in histories:
-                stat["account_id"] = account_id
-                stat["user_id"] = member["user_id"] if member is not None else None
-                stat["username"] = member["username"] if member is not None else None
-                stat["biography"] = member["biography"] if member is not None else None
-                stat["worktime_hour"] = isoduration_to_hour(stat["worktime"])
-
-            row_list.extend(histories)
-        return row_list
-
-    def list_cumulative_labor_time(self, project_id: str) -> None:
-        super().validate_project(project_id, project_member_roles=None)
-
-        account_stat_list = self.get_labor_time_per_user(project_id)
-        df = pandas.DataFrame(account_stat_list)
-        if len(df) > 0:
-            # 出力対象の列を指定する
-            target_df = df[
-                [
-                    "date",
-                    "account_id",
-                    "user_id",
-                    "username",
-                    "biography",
-                    "worktime_hour",
-                    "tasks_completed",
-                    "tasks_rejected",
-                ]
-            ]
-            annofabcli.utils.print_csv(target_df, output=self.output, to_csv_kwargs=self.csv_format)
-        else:
-            logger.error(f"出力対象データが0件のため、出力しません。")
-
-    def main(self):
-        args = self.args
-
-        project_id = args.project_id
-        self.list_cumulative_labor_time(project_id)
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    argument_parser = ArgumentParser(parser)
-
-    argument_parser.add_project_id()
-    argument_parser.add_csv_format()
-    argument_parser.add_output()
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def main(args):
-    service = build_annofabapi_resource_and_login(args)
-    facade = AnnofabApiFacade(service)
-    LaborTimePerUser(service, facade, args).main()
-
-
-def add_parser(subparsers: Optional[argparse._SubParsersAction] = None):
-    subcommand_name = "list_labor_time_per_user"
-    subcommand_help = "メンバ別の作業時間、完了数、差し戻し回数を日毎に出力する。"
-    description = "メンバ別の作業時間、完了数、差し戻し回数を日毎にCSV形式で出力する。"
-    parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description=description)
-    parse_args(parser)
-    return parser
diff --git a/annofabcli/statistics/list_task_progress.py b/annofabcli/statistics/list_task_progress.py
deleted file mode 100644
index f4312ffe..00000000
--- a/annofabcli/statistics/list_task_progress.py
+++ /dev/null
@@ -1,84 +0,0 @@
-import argparse
-import logging
-from typing import Any, Dict, List, Optional
-
-import pandas
-
-import annofabcli
-import annofabcli.common.cli
-from annofabcli import AnnofabApiFacade
-from annofabcli.common.cli import AbstractCommandLineInterface, ArgumentParser, build_annofabapi_resource_and_login
-
-logger = logging.getLogger(__name__)
-
-
-class TaskProgress(AbstractCommandLineInterface):
-    """
-    タスクの進捗状況を出力する。
-    """
-
-    def get_task_statistics(self, project_id: str) -> List[Dict[str, Any]]:
-        """
-        タスクの進捗状況をCSVに出力するための dict 配列を作成する。
-
-        Args:
-            project_id:
-
-        Returns:
-            タスクの進捗状況に対応するdict配列
-
-        """
-        task_statistics = self.service.wrapper.get_task_statistics(project_id)
-        row_list: List[Dict[str, Any]] = []
-        for stat_by_date in task_statistics:
-            date = stat_by_date["date"]
-            task_stat_list = stat_by_date["tasks"]
-            for task_stat in task_stat_list:
-                task_stat["date"] = date
-            row_list.extend(task_stat_list)
-        return row_list
-
-    def list_task_progress(self, project_id: str) -> None:
-        super().validate_project(project_id, project_member_roles=None)
-
-        task_stat_list = self.get_task_statistics(project_id)
-        if len(task_stat_list) == 0:
-            logger.info(f"タスクの進捗状況の情報がないため、出力しません。")
-            return
-
-        df = pandas.DataFrame(task_stat_list)
-        # 出力対象の列を指定する
-        target_df = df[["date", "phase", "status", "count"]]
-
-        annofabcli.utils.print_csv(target_df, output=self.output, to_csv_kwargs=self.csv_format)
-
-    def main(self):
-        args = self.args
-
-        project_id = args.project_id
-        self.list_task_progress(project_id)
-
-
-def parse_args(parser: argparse.ArgumentParser):
-    argument_parser = ArgumentParser(parser)
-
-    argument_parser.add_project_id()
-    argument_parser.add_csv_format()
-    argument_parser.add_output()
-
-    parser.set_defaults(subcommand_func=main)
-
-
-def main(args):
-    service = build_annofabapi_resource_and_login(args)
-    facade = AnnofabApiFacade(service)
-    TaskProgress(service, facade, args).main()
-
-
-def add_parser(subparsers: Optional[argparse._SubParsersAction] = None):
-    subcommand_name = "list_task_progress"
-    subcommand_help = "タスク進捗情報を出力する"
-    description = "タスク進捗状況をCSV形式で出力する。"
-    parser = annofabcli.common.cli.add_parser(subparsers, subcommand_name, subcommand_help, description=description)
-    parse_args(parser)
-    return parser
diff --git a/annofabcli/statistics/subcommand_statistics.py b/annofabcli/statistics/subcommand_statistics.py
index 88c0c5b1..4bf27fb7 100644
--- a/annofabcli/statistics/subcommand_statistics.py
+++ b/annofabcli/statistics/subcommand_statistics.py
@@ -5,10 +5,6 @@
 import annofabcli.common.cli
 import annofabcli.stat_visualization.merge_visualization_dir
 import annofabcli.statistics.list_annotation_count
-import annofabcli.statistics.list_by_date_user
-import annofabcli.statistics.list_cumulative_labor_time
-import annofabcli.statistics.list_labor_time_per_user
-import annofabcli.statistics.list_task_progress
 import annofabcli.statistics.list_worktime
 import annofabcli.statistics.summarize_task_count
 import annofabcli.statistics.summarize_task_count_by_task_id
@@ -23,10 +19,6 @@ def parse_args(parser: argparse.ArgumentParser):
 
     # サブコマンドの定義
     annofabcli.statistics.list_annotation_count.add_parser(subparsers)
-    annofabcli.statistics.list_by_date_user.add_parser(subparsers)
-    annofabcli.statistics.list_cumulative_labor_time.add_parser(subparsers)
-    annofabcli.statistics.list_labor_time_per_user.add_parser(subparsers)
-    annofabcli.statistics.list_task_progress.add_parser(subparsers)
     annofabcli.statistics.list_worktime.add_parser(subparsers)
     annofabcli.statistics.summarize_task_count.add_parser(subparsers)
     annofabcli.statistics.summarize_task_count_by_task_id.add_parser(subparsers)
diff --git a/annofabcli/statistics/visualization/dataframe/worktime_per_date.py b/annofabcli/statistics/visualization/dataframe/worktime_per_date.py
index 6964a1d7..be22bd31 100644
--- a/annofabcli/statistics/visualization/dataframe/worktime_per_date.py
+++ b/annofabcli/statistics/visualization/dataframe/worktime_per_date.py
@@ -102,7 +102,7 @@ def get_df_worktime(
     ]
     df.fillna({c: 0 for c in value_columns}, inplace=True)
 
-    df = df.merge(df_member, how="left", on="user_id")
+    df = df.merge(df_member, how="left", on="account_id")
     return df[
         [
             "date",
diff --git a/annofabcli/supplementary/list_supplementary_data.py b/annofabcli/supplementary/list_supplementary_data.py
index e6830a6c..44fb810d 100644
--- a/annofabcli/supplementary/list_supplementary_data.py
+++ b/annofabcli/supplementary/list_supplementary_data.py
@@ -29,6 +29,7 @@ def get_input_data_id_from_task(self, project_id: str, task_id_list: List[str])
             task = self.service.wrapper.get_task_or_none(project_id, task_id)
             if task is None:
                 logger.warning(f"task_id='{task_id}'のタスクが見つかりませんでした。")
+                continue
             all_input_data_id_list.extend(task["input_data_id_list"])
         return all_input_data_id_list
 
@@ -44,7 +45,9 @@ def get_all_supplementary_data_list(
             if (index + 1) % 100 == 0:
                 logger.debug(f"{index+1} 件目の入力データを取得します。")
 
-            supplementary_data_list = self.get_supplementary_data_list(project_id, input_data_id)
+            supplementary_data_list = self.service.wrapper.get_supplementary_data_list_or_none(
+                project_id, input_data_id
+            )
             if supplementary_data_list is not None:
                 all_supplementary_data_list.extend(supplementary_data_list)
             else:
diff --git a/annofabcli/task/delete_tasks.py b/annofabcli/task/delete_tasks.py
index 18a8b81f..44f081d3 100644
--- a/annofabcli/task/delete_tasks.py
+++ b/annofabcli/task/delete_tasks.py
@@ -20,11 +20,6 @@ class DeleteTask(AbstractCommandLineInterface):
     アノテーションが付与されていないタスクを削除する
     """
 
-    @annofabcli.utils.allow_404_error
-    def get_task(self, project_id: str, task_id: str) -> Dict[str, Any]:
-        task, _ = self.service.api.get_task(project_id, task_id)
-        return task
-
     def confirm_delete_task(self, task_id: str) -> bool:
         message_for_confirm = f"タスク'{task_id}' を削除しますか？"
         return self.confirm_processing(message_for_confirm)
@@ -58,7 +53,7 @@ def delete_task(
             True: タスクを削除した。False: タスクを削除しなかった。
 
         """
-        task = self.get_task(project_id, task_id)
+        task = self.service.wrapper.get_task_or_none(project_id, task_id)
         if task is None:
             logger.info(f"task_id={task_id} のタスクは存在しません。")
             return False
diff --git a/annofabcli/task/list_tasks.py b/annofabcli/task/list_tasks.py
index 3d01e6e4..0e628dbd 100644
--- a/annofabcli/task/list_tasks.py
+++ b/annofabcli/task/list_tasks.py
@@ -23,11 +23,6 @@ def __init__(self, service: annofabapi.Resource, project_id: str):
         self.project_id = project_id
         self.visualize = AddProps(self.service, project_id)
 
-    @annofabcli.utils.allow_404_error
-    def get_task(self, project_id: str, task_id: str) -> Task:
-        task, _ = self.service.api.get_task(project_id, task_id)
-        return task
-
     def get_task_list_from_task_id(self, project_id: str, task_id_list: List[str]) -> List[Task]:
         task_list = []
         logger.debug(f"{len(task_id_list)}件のタスクを取得します。")
@@ -35,7 +30,7 @@ def get_task_list_from_task_id(self, project_id: str, task_id_list: List[str]) -
             if (index + 1) % 100 == 0:
                 logger.debug(f"{index+1} 件のタスクを取得します。")
 
-            task = self.get_task(project_id, task_id)
+            task = self.service.wrapper.get_task_or_none(project_id, task_id)
             if task is not None:
                 task_list.append(self.visualize.add_properties_to_task(task))
             else:
diff --git a/annofabcli/task/reject_tasks.py b/annofabcli/task/reject_tasks.py
index cab59c48..0d44702b 100644
--- a/annofabcli/task/reject_tasks.py
+++ b/annofabcli/task/reject_tasks.py
@@ -211,8 +211,11 @@ def reject_task_with_adding_comment(
         if task["status"] == TaskStatus.COMPLETE.value and cancel_acceptance and not dryrun:
             self._cancel_acceptance(task)
 
+        is_changed_to_working_status = False
         if inspection_comment is not None:
+            # 検査コメントを付与するには「作業中」状態に変更して、担当者を自分自身に変更する必要がある。
             changed_task = self.change_to_working_status(project_id, task)
+            is_changed_to_working_status = True
             try:
                 # 検査コメントを付与する
                 if not dryrun:
@@ -246,15 +249,11 @@ def reject_task_with_adding_comment(
             return True
 
         except requests.exceptions.HTTPError as e:
-            logger.warning(e)
-            logger.warning(f"{logging_prefix} : task_id = {task_id} タスクの差し戻しに失敗")
+            logger.warning(f"{logging_prefix} : task_id = {task_id} タスクの差し戻しに失敗しました。 :: {e}")
 
+            # working中状態のままだと作業時間が増え続けるので、休憩中モードにする。
             if not dryrun:
-                new_task = self.service.wrapper.get_task_or_none(project_id, task_id)
-                if (
-                    new_task["status"] == TaskStatus.WORKING.value
-                    and new_task["account_id"] == self.service.api.account_id
-                ):
+                if is_changed_to_working_status:
                     self.facade.change_to_break_phase(project_id, task_id)
             return False
 
diff --git a/annofabcli/task_history/list_task_history.py b/annofabcli/task_history/list_task_history.py
index 7011050d..725acc78 100644
--- a/annofabcli/task_history/list_task_history.py
+++ b/annofabcli/task_history/list_task_history.py
@@ -4,7 +4,6 @@
 
 import annofabapi
 from annofabapi.models import TaskHistory
-from annofabapi.utils import allow_404_error
 
 import annofabcli
 from annofabcli import AnnofabApiFacade
@@ -34,15 +33,11 @@ def filter_task_history_dict(task_history_dict: TaskHistoryDict, task_id_list: L
                 filtered_task_history_dict[task_id] = task_history_list
         return filtered_task_history_dict
 
-    @allow_404_error
-    def get_task_histories(self, project_id: str, task_id: str) -> Optional[List[TaskHistory]]:
-        return self.service.api.get_task_histories(project_id, task_id)[0]
-
     def get_task_history_dict_from_project_id(self, project_id: str, task_id_list: List[str]) -> TaskHistoryDict:
         logger.info(f"{len(task_id_list)} 件のタスクの履歴情報を取得します。")
         task_history_dict: TaskHistoryDict = {}
         for task_index, task_id in enumerate(task_id_list):
-            task_history_list = self.get_task_histories(project_id, task_id)
+            task_history_list = self.service.wrapper.get_task_histories_or_none(project_id, task_id)
             if (task_index + 1) % 100 == 0:
                 logger.info(f"{task_index+1} 件のタスクの履歴情報を取得しました。")
             if task_history_list is not None:
diff --git a/docs/command_reference/statistics/index.rst b/docs/command_reference/statistics/index.rst
index 3ea9775c..4d7081f1 100644
--- a/docs/command_reference/statistics/index.rst
+++ b/docs/command_reference/statistics/index.rst
@@ -17,10 +17,6 @@ Available Commands
 
 
    list_annotation_count
-   list_by_date_user   
-   list_cumulative_labor_time
-   list_labor_time_per_user
-   list_task_progress  
    list_worktime
    summarize_task_count
    summarize_task_count_by_task_id
diff --git a/docs/command_reference/statistics/list_by_date_user.rst b/docs/command_reference/statistics/list_by_date_user.rst
deleted file mode 100644
index b64ca511..00000000
--- a/docs/command_reference/statistics/list_by_date_user.rst
+++ /dev/null
@@ -1,78 +0,0 @@
-==========================================
-statistics list_by_date_user
-==========================================
-
-Description
-=================================
-
-タスク数や作業時間などの情報を、日ごとユーザごとに出力します。
-
-
-
-Examples
-=================================
-
-基本的な使い方
---------------------------
-
-タスク履歴全件ファイルから、CSVファイルを出力します。
-
-.. code-block::
-
-    $ annofabcli statistics list_by_date_user --project_id prj1
-
-集計期間を指定することも可能です。
-
-.. code-block::
-
-    $ annofabcli statistics list_by_date_user --project_id prj1 \
-    --start_date 2020-01-01 --end_date 2020-01-31
-
-
-
-
-出力結果
-=================================
-
-
-.. code-block::
-
-    $ annofabcli statistics list_by_date_user --project_id prj1 --output out.csv
-
-
-.. csv-table:: out.csv
-   :header: date,user_id,username,biography,worktime_hour,annotation_submitted_task_count,inspection_submitted_task_count,acceptance_submitted_task_count,rejected_task_count
-
-
-    2020-12-15,user1,user1,,3.844,28,0,0,4
-    2020-12-16,user1,user2,,1.047,0,0,16,1
-    2020-12-16,user2,user3,,2.834,0,0,6
-
-
-
-各列の詳細は以下の通りです。
-
-* worktime_hour: 作業時間[hour]
-* annotation_submitted_task_count: 教師付フェーズのタスクを提出した回数
-* inspection_submitted_task_count: 検査フェーズのタスクを差し戻しまたは合格にしたした回数
-* acceptance_submitted_task_count: 受入フェーズのタスクを差し戻しまたは合格にしたした回数
-* rejected_task_count: 差し戻された回数
-
-
-.. warning::
-
-    以下の数値は直感的でない値になる場合があります。信用しないでください。
-
-    * annotation_submitted_task_count
-    * inspection_submitted_task_count
-    * acceptance_submitted_task_count
-    * rejected_task_count
-
-Usage Details
-=================================
-
-.. argparse::
-   :ref: annofabcli.statistics.list_by_date_user.add_parser
-   :prog: annofabcli statistics list_by_date_user
-   :nosubcommands:
-   :nodefaultconst:
diff --git a/docs/command_reference/statistics/list_cumulative_labor_time.rst b/docs/command_reference/statistics/list_cumulative_labor_time.rst
deleted file mode 100644
index 4d08d2e0..00000000
--- a/docs/command_reference/statistics/list_cumulative_labor_time.rst
+++ /dev/null
@@ -1,55 +0,0 @@
-==========================================
-statistics list_cumulative_labor_time
-==========================================
-
-Description
-=================================
-
-日ごと、フェーズごとの累積作業時間をCSV形式で出力する。
-
-
-
-
-
-Examples
-=================================
-
-基本的な使い方
---------------------------
-
-
-.. code-block::
-
-    $ annofabcli statistics list_cumulative_labor_time --project_id prj1
-
-
-
-
-
-出力結果
-=================================
-
-
-.. code-block::
-
-    $ annofabcli statistics list_cumulative_labor_time --project_id prj1 --output out.csv
-
-.. csv-table:: out.csv
-   :header: date,phase,worktime_hour
-
-
-    2020-12-15,acceptance,1.12289361111111
-    2020-12-15,annotation,6.67816833333333
-    2020-12-16,acceptance,1.72973638888889
-    2020-12-16,annotation,13.7682875
-    2020-12-17,acceptance,2.6953075
-    2020-12-17,annotation,16.3832388888889
-
-Usage Details
-=================================
-
-.. argparse::
-   :ref: annofabcli.statistics.list_cumulative_labor_time.add_parser
-   :prog: annofabcli statistics list_cumulative_labor_time
-   :nosubcommands:
-   :nodefaultconst:
diff --git a/docs/command_reference/statistics/list_labor_time_per_user.rst b/docs/command_reference/statistics/list_labor_time_per_user.rst
deleted file mode 100644
index 7ccf6490..00000000
--- a/docs/command_reference/statistics/list_labor_time_per_user.rst
+++ /dev/null
@@ -1,66 +0,0 @@
-==========================================
-statistics list_labor_time_per_user
-==========================================
-
-Description
-=================================
-
-メンバ別の作業時間、完了数、差し戻し回数を日毎にCSV形式で出力する。
-
-
-
-
-
-
-Examples
-=================================
-
-基本的な使い方
---------------------------
-
-
-.. code-block::
-
-    $ annofabcli statistics list_labor_time_per_user --project_id prj1
-
-
-
-
-
-出力結果
-=================================
-
-
-.. code-block::
-
-    $ annofabcli statistics list_labor_time_per_user --project_id prj1 --output out.csv
-
-
-
-.. csv-table:: out.csv
-   :header: date,account_id,user_id,username,biography,worktime_hour,tasks_completed,tasks_rejected
-
-    2020-12-15,account1,user1,username1,,2.834,19,6
-    2020-12-16,account1,user1,username1,,3.417,36,2
-    2020-12-17,account2,user2,username2,,0.094,0,3
-
-
-
-各列の詳細を以下に示します。
-
-* worktime_hour: 作業時間[hour]
-* tasks_completed: 完了したタスク数
-* tasks_rejected: 差し戻された回数
-
-.. warning::
-
-    ``tasks_completed`` , ``tasks_rejected`` は直感的でない数字になる場合があります。信用しないでください。
-
-Usage Details
-=================================
-
-.. argparse::
-   :ref: annofabcli.statistics.list_labor_time_per_user.add_parser
-   :prog: annofabcli statistics list_labor_time_per_user
-   :nosubcommands:
-   :nodefaultconst:
diff --git a/docs/command_reference/statistics/list_task_progress.rst b/docs/command_reference/statistics/list_task_progress.rst
deleted file mode 100644
index db8e857a..00000000
--- a/docs/command_reference/statistics/list_task_progress.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-==========================================
-statistics list_task_progress
-==========================================
-
-Description
-=================================
-
-タスク進捗状況をCSV形式で出力する。
-
-
-
-Examples
-=================================
-
-基本的な使い方
---------------------------
-
-
-.. code-block::
-
-    $ annofabcli statistics list_task_progress --project_id prj1
-
-
-
-出力結果
-=================================
-
-
-.. code-block::
-
-    $ annofabcli statistics list_task_progress --project_id prj1 --output out.csv
-
-
-.. csv-table:: out.csv
-   :header: date,phase,status,count
-
-    2020-12-15,annotation,break,1
-    2020-12-15,annotation,not_started,59
-    2020-12-15,annotation,on_hold,3
-    2020-12-15,acceptance,not_started,29
-    2020-12-15,acceptance,complete,8
-    2020-12-16,annotation,not_started,50
-    2020-12-16,acceptance,not_started,90
-    2020-12-16,acceptance,complete,10
-
-Usage Details
-=================================
-
-.. argparse::
-   :ref: annofabcli.statistics.list_task_progress.add_parser
-   :prog: annofabcli statistics list_task_progress
-   :nosubcommands:
-   :nodefaultconst:
diff --git a/poetry.lock b/poetry.lock
index d0791e46..d36b3910 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -16,11 +16,11 @@ python-versions = "*"
 
 [[package]]
 name = "annofabapi"
-version = "0.51.1"
+version = "0.52.3"
 description = "Python Clinet Library of AnnoFab WebAPI (https://annofab.com/docs/api/)"
 category = "main"
 optional = false
-python-versions = ">=3.6.2,<4.0.0"
+python-versions = ">=3.7,<4.0"
 
 [package.dependencies]
 backoff = "*"
@@ -38,11 +38,11 @@ python-versions = "*"
 
 [[package]]
 name = "astroid"
-version = "2.9.0"
+version = "2.9.2"
 description = "An abstract syntax tree for Python with inference support."
 category = "dev"
 optional = false
-python-versions = "~=3.6"
+python-versions = ">=3.6.2"
 
 [package.dependencies]
 lazy-object-proxy = ">=1.4.0"
@@ -60,17 +60,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "attrs"
-version = "21.2.0"
+version = "21.4.0"
 description = "Classes Without Boilerplate"
 category = "dev"
 optional = false
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"]
+dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
 docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"]
+tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
+tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "cloudpickle"]
 
 [[package]]
 name = "autoflake"
@@ -654,11 +654,11 @@ python-versions = "*"
 
 [[package]]
 name = "pillow"
-version = "8.4.0"
+version = "9.0.0"
 description = "Python Imaging Library (Fork)"
 category = "main"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [[package]]
 name = "platformdirs"
@@ -749,7 +749,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "pygments"
-version = "2.10.0"
+version = "2.11.1"
 description = "Pygments is a syntax highlighting package written in Python."
 category = "dev"
 optional = false
@@ -935,7 +935,7 @@ python-versions = ">=3.6"
 
 [[package]]
 name = "requests"
-version = "2.26.0"
+version = "2.27.0"
 description = "Python HTTP for Humans."
 category = "main"
 optional = false
@@ -1163,7 +1163,7 @@ python-versions = "*"
 
 [[package]]
 name = "types-requests"
-version = "2.26.2"
+version = "2.26.3"
 description = "Typing stubs for requests"
 category = "dev"
 optional = false
@@ -1220,20 +1220,20 @@ python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
 
 [[package]]
 name = "zipp"
-version = "3.6.0"
+version = "3.7.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.extras]
 docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
+testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"]
 
 [metadata]
 lock-version = "1.1"
 python-versions = "^3.7.1"
-content-hash = "62b1a9c58d92d79d1e890de07fc6659d51f506834f9fe7c0f7d778ab0e12e798"
+content-hash = "ff05c30c6bb4d231e0c2875d1cebaf4865b5c0982cec93ac253408eb4ff35603"
 
 [metadata.files]
 alabaster = [
@@ -1245,24 +1245,24 @@ altgraph = [
     {file = "altgraph-0.17.2.tar.gz", hash = "sha256:ebf2269361b47d97b3b88e696439f6e4cbc607c17c51feb1754f90fb79839158"},
 ]
 annofabapi = [
-    {file = "annofabapi-0.51.1-py3-none-any.whl", hash = "sha256:c111085ad151c3282a349cc4fe63f81be5647a22ee77b19b4b78d46a849a8140"},
-    {file = "annofabapi-0.51.1.tar.gz", hash = "sha256:601cc0601bfb7bbc1e9d78f9494be57aa92f3804776625e52b9cb9468771eda2"},
+    {file = "annofabapi-0.52.3-py3-none-any.whl", hash = "sha256:7820f242b7bfb90bbd25e01e1c52d3186ed8cef52204d6f20b4ec8512b78071c"},
+    {file = "annofabapi-0.52.3.tar.gz", hash = "sha256:5a890db9f9080cc416aa1b5803bfbf7b2050bae3bec260d937e453dc3009a434"},
 ]
 appnope = [
     {file = "appnope-0.1.2-py2.py3-none-any.whl", hash = "sha256:93aa393e9d6c54c5cd570ccadd8edad61ea0c4b9ea7a01409020c9aa019eb442"},
     {file = "appnope-0.1.2.tar.gz", hash = "sha256:dd83cd4b5b460958838f6eb3000c660b1f9caf2a5b1de4264e941512f603258a"},
 ]
 astroid = [
-    {file = "astroid-2.9.0-py3-none-any.whl", hash = "sha256:776ca0b748b4ad69c00bfe0fff38fa2d21c338e12c84aa9715ee0d473c422778"},
-    {file = "astroid-2.9.0.tar.gz", hash = "sha256:5939cf55de24b92bda00345d4d0659d01b3c7dafb5055165c330bc7c568ba273"},
+    {file = "astroid-2.9.2-py3-none-any.whl", hash = "sha256:aa296702f1a5c3102c860de49473aaa90a7f6d221555d5cf2678940a9be32a4e"},
+    {file = "astroid-2.9.2.tar.gz", hash = "sha256:72ace9c3333e274e9248168fc4f3e300da8545af1c303bd69197027f49e2bfff"},
 ]
 atomicwrites = [
     {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"},
     {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"},
 ]
 attrs = [
-    {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"},
-    {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"},
+    {file = "attrs-21.4.0-py2.py3-none-any.whl", hash = "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4"},
+    {file = "attrs-21.4.0.tar.gz", hash = "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd"},
 ]
 autoflake = [
     {file = "autoflake-1.4.tar.gz", hash = "sha256:61a353012cff6ab94ca062823d1fb2f692c4acda51c76ff83a8d77915fba51ea"},
@@ -1730,47 +1730,38 @@ pickleshare = [
     {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
 ]
 pillow = [
-    {file = "Pillow-8.4.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:81f8d5c81e483a9442d72d182e1fb6dcb9723f289a57e8030811bac9ea3fef8d"},
-    {file = "Pillow-8.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f97cfb1e5a392d75dd8b9fd274d205404729923840ca94ca45a0af57e13dbe6"},
-    {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb9fc393f3c61f9054e1ed26e6fe912c7321af2f41ff49d3f83d05bacf22cc78"},
-    {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d82cdb63100ef5eedb8391732375e6d05993b765f72cb34311fab92103314649"},
-    {file = "Pillow-8.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc1afda735a8d109007164714e73771b499768b9bb5afcbbee9d0ff374b43f"},
-    {file = "Pillow-8.4.0-cp310-cp310-win32.whl", hash = "sha256:e3dacecfbeec9a33e932f00c6cd7996e62f53ad46fbe677577394aaa90ee419a"},
-    {file = "Pillow-8.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:620582db2a85b2df5f8a82ddeb52116560d7e5e6b055095f04ad828d1b0baa39"},
-    {file = "Pillow-8.4.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:1bc723b434fbc4ab50bb68e11e93ce5fb69866ad621e3c2c9bdb0cd70e345f55"},
-    {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:72cbcfd54df6caf85cc35264c77ede902452d6df41166010262374155947460c"},
-    {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70ad9e5c6cb9b8487280a02c0ad8a51581dcbbe8484ce058477692a27c151c0a"},
-    {file = "Pillow-8.4.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25a49dc2e2f74e65efaa32b153527fc5ac98508d502fa46e74fa4fd678ed6645"},
-    {file = "Pillow-8.4.0-cp36-cp36m-win32.whl", hash = "sha256:93ce9e955cc95959df98505e4608ad98281fff037350d8c2671c9aa86bcf10a9"},
-    {file = "Pillow-8.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2e4440b8f00f504ee4b53fe30f4e381aae30b0568193be305256b1462216feff"},
-    {file = "Pillow-8.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8c803ac3c28bbc53763e6825746f05cc407b20e4a69d0122e526a582e3b5e153"},
-    {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c8a17b5d948f4ceeceb66384727dde11b240736fddeda54ca740b9b8b1556b29"},
-    {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1394a6ad5abc838c5cd8a92c5a07535648cdf6d09e8e2d6df916dfa9ea86ead8"},
-    {file = "Pillow-8.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:792e5c12376594bfcb986ebf3855aa4b7c225754e9a9521298e460e92fb4a488"},
-    {file = "Pillow-8.4.0-cp37-cp37m-win32.whl", hash = "sha256:d99ec152570e4196772e7a8e4ba5320d2d27bf22fdf11743dd882936ed64305b"},
-    {file = "Pillow-8.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:7b7017b61bbcdd7f6363aeceb881e23c46583739cb69a3ab39cb384f6ec82e5b"},
-    {file = "Pillow-8.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:d89363f02658e253dbd171f7c3716a5d340a24ee82d38aab9183f7fdf0cdca49"},
-    {file = "Pillow-8.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a0956fdc5defc34462bb1c765ee88d933239f9a94bc37d132004775241a7585"},
-    {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5b7bb9de00197fb4261825c15551adf7605cf14a80badf1761d61e59da347779"},
-    {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72b9e656e340447f827885b8d7a15fc8c4e68d410dc2297ef6787eec0f0ea409"},
-    {file = "Pillow-8.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5a4532a12314149d8b4e4ad8ff09dde7427731fcfa5917ff16d0291f13609df"},
-    {file = "Pillow-8.4.0-cp38-cp38-win32.whl", hash = "sha256:82aafa8d5eb68c8463b6e9baeb4f19043bb31fefc03eb7b216b51e6a9981ae09"},
-    {file = "Pillow-8.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:066f3999cb3b070a95c3652712cffa1a748cd02d60ad7b4e485c3748a04d9d76"},
-    {file = "Pillow-8.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:5503c86916d27c2e101b7f71c2ae2cddba01a2cf55b8395b0255fd33fa4d1f1a"},
-    {file = "Pillow-8.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4acc0985ddf39d1bc969a9220b51d94ed51695d455c228d8ac29fcdb25810e6e"},
-    {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b052a619a8bfcf26bd8b3f48f45283f9e977890263e4571f2393ed8898d331b"},
-    {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:493cb4e415f44cd601fcec11c99836f707bb714ab03f5ed46ac25713baf0ff20"},
-    {file = "Pillow-8.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8831cb7332eda5dc89b21a7bce7ef6ad305548820595033a4b03cf3091235ed"},
-    {file = "Pillow-8.4.0-cp39-cp39-win32.whl", hash = "sha256:5e9ac5f66616b87d4da618a20ab0a38324dbe88d8a39b55be8964eb520021e02"},
-    {file = "Pillow-8.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:3eb1ce5f65908556c2d8685a8f0a6e989d887ec4057326f6c22b24e8a172c66b"},
-    {file = "Pillow-8.4.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ddc4d832a0f0b4c52fff973a0d44b6c99839a9d016fe4e6a1cb8f3eea96479c2"},
-    {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3e5ddc44c14042f0844b8cf7d2cd455f6cc80fd7f5eefbe657292cf601d9ad"},
-    {file = "Pillow-8.4.0-pp36-pypy36_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c70e94281588ef053ae8998039610dbd71bc509e4acbc77ab59d7d2937b10698"},
-    {file = "Pillow-8.4.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:3862b7256046fcd950618ed22d1d60b842e3a40a48236a5498746f21189afbbc"},
-    {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4901622493f88b1a29bd30ec1a2f683782e57c3c16a2dbc7f2595ba01f639df"},
-    {file = "Pillow-8.4.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c471a734240653a0ec91dec0996696eea227eafe72a33bd06c92697728046b"},
-    {file = "Pillow-8.4.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:244cf3b97802c34c41905d22810846802a3329ddcb93ccc432870243211c79fc"},
-    {file = "Pillow-8.4.0.tar.gz", hash = "sha256:b8e2f83c56e141920c39464b852de3719dfbfb6e3c99a2d8da0edf4fb33176ed"},
+    {file = "Pillow-9.0.0-cp310-cp310-macosx_10_10_universal2.whl", hash = "sha256:113723312215b25c22df1fdf0e2da7a3b9c357a7d24a93ebbe80bfda4f37a8d4"},
+    {file = "Pillow-9.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:bb47a548cea95b86494a26c89d153fd31122ed65255db5dcbc421a2d28eb3379"},
+    {file = "Pillow-9.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31b265496e603985fad54d52d11970383e317d11e18e856971bdbb86af7242a4"},
+    {file = "Pillow-9.0.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d154ed971a4cc04b93a6d5b47f37948d1f621f25de3e8fa0c26b2d44f24e3e8f"},
+    {file = "Pillow-9.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80fe92813d208ce8aa7d76da878bdc84b90809f79ccbad2a288e9bcbeac1d9bd"},
+    {file = "Pillow-9.0.0-cp310-cp310-win32.whl", hash = "sha256:d5dcea1387331c905405b09cdbfb34611050cc52c865d71f2362f354faee1e9f"},
+    {file = "Pillow-9.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:52abae4c96b5da630a8b4247de5428f593465291e5b239f3f843a911a3cf0105"},
+    {file = "Pillow-9.0.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:72c3110228944019e5f27232296c5923398496b28be42535e3b2dc7297b6e8b6"},
+    {file = "Pillow-9.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97b6d21771da41497b81652d44191489296555b761684f82b7b544c49989110f"},
+    {file = "Pillow-9.0.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72f649d93d4cc4d8cf79c91ebc25137c358718ad75f99e99e043325ea7d56100"},
+    {file = "Pillow-9.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7aaf07085c756f6cb1c692ee0d5a86c531703b6e8c9cae581b31b562c16b98ce"},
+    {file = "Pillow-9.0.0-cp37-cp37m-win32.whl", hash = "sha256:03b27b197deb4ee400ed57d8d4e572d2d8d80f825b6634daf6e2c18c3c6ccfa6"},
+    {file = "Pillow-9.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:a09a9d4ec2b7887f7a088bbaacfd5c07160e746e3d47ec5e8050ae3b2a229e9f"},
+    {file = "Pillow-9.0.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:490e52e99224858f154975db61c060686df8a6b3f0212a678e5d2e2ce24675c9"},
+    {file = "Pillow-9.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:500d397ddf4bbf2ca42e198399ac13e7841956c72645513e8ddf243b31ad2128"},
+    {file = "Pillow-9.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ebd8b9137630a7bbbff8c4b31e774ff05bbb90f7911d93ea2c9371e41039b52"},
+    {file = "Pillow-9.0.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd0e5062f11cb3e730450a7d9f323f4051b532781026395c4323b8ad055523c4"},
+    {file = "Pillow-9.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f3b4522148586d35e78313db4db0df4b759ddd7649ef70002b6c3767d0fdeb7"},
+    {file = "Pillow-9.0.0-cp38-cp38-win32.whl", hash = "sha256:0b281fcadbb688607ea6ece7649c5d59d4bbd574e90db6cd030e9e85bde9fecc"},
+    {file = "Pillow-9.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:b5050d681bcf5c9f2570b93bee5d3ec8ae4cf23158812f91ed57f7126df91762"},
+    {file = "Pillow-9.0.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:c2067b3bb0781f14059b112c9da5a91c80a600a97915b4f48b37f197895dd925"},
+    {file = "Pillow-9.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2d16b6196fb7a54aff6b5e3ecd00f7c0bab1b56eee39214b2b223a9d938c50af"},
+    {file = "Pillow-9.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98cb63ca63cb61f594511c06218ab4394bf80388b3d66cd61d0b1f63ee0ea69f"},
+    {file = "Pillow-9.0.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bc462d24500ba707e9cbdef436c16e5c8cbf29908278af053008d9f689f56dee"},
+    {file = "Pillow-9.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3586e12d874ce2f1bc875a3ffba98732ebb12e18fb6d97be482bd62b56803281"},
+    {file = "Pillow-9.0.0-cp39-cp39-win32.whl", hash = "sha256:68e06f8b2248f6dc8b899c3e7ecf02c9f413aab622f4d6190df53a78b93d97a5"},
+    {file = "Pillow-9.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:6579f9ba84a3d4f1807c4aab4be06f373017fc65fff43498885ac50a9b47a553"},
+    {file = "Pillow-9.0.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:47f5cf60bcb9fbc46011f75c9b45a8b5ad077ca352a78185bd3e7f1d294b98bb"},
+    {file = "Pillow-9.0.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fd8053e1f8ff1844419842fd474fc359676b2e2a2b66b11cc59f4fa0a301315"},
+    {file = "Pillow-9.0.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c5439bfb35a89cac50e81c751317faea647b9a3ec11c039900cd6915831064d"},
+    {file = "Pillow-9.0.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95545137fc56ce8c10de646074d242001a112a92de169986abd8c88c27566a05"},
+    {file = "Pillow-9.0.0.tar.gz", hash = "sha256:ee6e2963e92762923956fe5d3479b1fdc3b76c83f290aad131a2f98c3df0593e"},
 ]
 platformdirs = [
     {file = "platformdirs-2.4.1-py3-none-any.whl", hash = "sha256:1d7385c7db91728b83efd0ca99a5afb296cab9d0ed8313a45ed8ba17967ecfca"},
@@ -1805,8 +1796,8 @@ pyflakes = [
     {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
 ]
 pygments = [
-    {file = "Pygments-2.10.0-py3-none-any.whl", hash = "sha256:b8e67fe6af78f492b3c4b3e2970c0624cbf08beb1e493b2c99b9fa1b67a20380"},
-    {file = "Pygments-2.10.0.tar.gz", hash = "sha256:f398865f7eb6874156579fdf36bc840a03cab64d1cde9e93d68f46a425ec52c6"},
+    {file = "Pygments-2.11.1-py3-none-any.whl", hash = "sha256:9135c1af61eec0f650cd1ea1ed8ce298e54d56bcd8cc2ef46edd7702c171337c"},
+    {file = "Pygments-2.11.1.tar.gz", hash = "sha256:59b895e326f0fb0d733fd28c6839bd18ad0687ba20efc26d4277fd1d30b971f4"},
 ]
 pyinstaller = [
     {file = "pyinstaller-4.5.1-py3-none-macosx_10_13_universal2.whl", hash = "sha256:ecc2baadeeefd2b6fbf39d13c65d4aa603afdda1c6aaaebc4577ba72893fee9e"},
@@ -1901,8 +1892,8 @@ pyyaml = [
     {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
 ]
 requests = [
-    {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
-    {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
+    {file = "requests-2.27.0-py2.py3-none-any.whl", hash = "sha256:f71a09d7feba4a6b64ffd8e9d9bc60f9bf7d7e19fd0e04362acb1cfc2e3d98df"},
+    {file = "requests-2.27.0.tar.gz", hash = "sha256:8e5643905bf20a308e25e4c1dd379117c09000bf8a82ebccc462cfb1b34a16b5"},
 ]
 six = [
     {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
@@ -2037,8 +2028,8 @@ types-pyyaml = [
     {file = "types_PyYAML-6.0.1-py3-none-any.whl", hash = "sha256:d5b318269652e809b5c30a5fe666c50159ab80bfd41cd6bafe655bf20b29fcba"},
 ]
 types-requests = [
-    {file = "types-requests-2.26.2.tar.gz", hash = "sha256:0e22d9cdeff4c3eb068eb883d59b127c98d80525f3d0412a1c4499c6ae1f711e"},
-    {file = "types_requests-2.26.2-py3-none-any.whl", hash = "sha256:fabe1acc784708ac798ced6373568465b93642c8aa1ebd33e2921b60d4e7aa29"},
+    {file = "types-requests-2.26.3.tar.gz", hash = "sha256:d63fa617846dcefff5aa2d59e47ab4ffd806e4bb0567115f7adbb5e438302fe4"},
+    {file = "types_requests-2.26.3-py3-none-any.whl", hash = "sha256:ad18284931c5ddbf050ccdd138f200d18fd56f88aa3567019d8da9b2d4fe0344"},
 ]
 typing-extensions = [
     {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"},
@@ -2111,6 +2102,6 @@ wrapt = [
     {file = "wrapt-1.13.3.tar.gz", hash = "sha256:1fea9cd438686e6682271d36f3481a9f3636195578bab9ca3382e2f5f01fc185"},
 ]
 zipp = [
-    {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
-    {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
+    {file = "zipp-3.7.0-py3-none-any.whl", hash = "sha256:b47250dd24f92b7dd6a0a8fc5244da14608f3ca90a5efcd37a3b1642fac9a375"},
+    {file = "zipp-3.7.0.tar.gz", hash = "sha256:9f50f446828eb9d45b267433fd3e9da8d801f614129124863f9c51ebceafb87d"},
 ]
diff --git a/pyproject.toml b/pyproject.toml
index 78cfe542..74715831 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "annofabcli"
-version = "1.53.9"
+version = "1.54.0"
 description = "Utility Command Line Interface for AnnoFab"
 authors = ["yuji38kwmt"]
 license = "MIT"
@@ -32,7 +32,7 @@ more-itertools = "*"
 jmespath = "*"
 pyquery = "*"
 isodate = "*"
-annofabapi = ">=0.49.0"
+annofabapi = ">=0.52.3"
 python-datauri = "*"
 pandas = "*"
 bokeh = "^2.4"
@@ -47,7 +47,7 @@ pytest-cov = "*"
 # format library
 isort = "*"
 autoflake = "*"
-black = {version = "^21.9b0", allow-prereleases = true}
+black = {version = "^21.12b0", allow-prereleases = true}
 
 # lint library
 flake8 = "*"


Test patch:
diff --git a/tests/data/experimental/list_labor_worktime/intermediate.csv b/tests/data/experimental/list_labor_worktime/intermediate.csv
deleted file mode 100755
index 6b672003..00000000
--- a/tests/data/experimental/list_labor_worktime/intermediate.csv
+++ /dev/null
@@ -1,5 +0,0 @@
-date,project_id,project_title,account_id,user_id,username,biography,worktime_planned,worktime_actual,worktime_monitored,working_description
-2021-08-17,prj1,prj1,user1,user1,user1,XXX,0,2,1,
-2021-08-17,prj1,prj1,user2,user1,user2,YYY,2,3,4,memo
-2021-08-20,prj2,prj2,user1,user1,user1,XXX,0,2,1,
-2021-08-29,prj2,prj2,user2,user1,user2,YYY,2,3,4,
diff --git a/tests/data/experimental/task.json b/tests/data/experimental/task.json
deleted file mode 100644
index 137de170..00000000
--- a/tests/data/experimental/task.json
+++ /dev/null
@@ -1,25 +0,0 @@
-[
-  {
-    "project_id": "58a2a621-7d4b-41e7-927b-cdc570c1114a",
-    "task_id": "0d97e5e0-a737-47ae-8b8c-f09194a2a9fd",
-    "phase": "annotation",
-    "phase_stage": 1,
-    "status": "break",
-    "input_data_id_list": [
-      "7115b8fb-6850-4b66-9f34-211312b2b9c5"
-    ],
-    "account_id": "00589ed0-dd63-40db-abb2-dfe5e13c8299",
-    "histories_by_phase": [
-      {
-        "account_id": "00589ed0-dd63-40db-abb2-dfe5e13c8299",
-        "phase": "annotation",
-        "phase_stage": 1
-      }
-    ],
-    "work_time_span": 539662,
-    "number_of_rejections": 0,
-    "started_datetime": "2019-05-08T13:53:21.338+09:00",
-    "updated_datetime": "2019-05-08T14:15:07.318+09:00",
-    "sampling": null
-  }
-]
\ No newline at end of file
diff --git a/tests/data/experimental/worktime-per-project-date.csv b/tests/data/experimental/worktime-per-project-date.csv
deleted file mode 100644
index f4a99499..00000000
--- a/tests/data/experimental/worktime-per-project-date.csv
+++ /dev/null
@@ -1,3 +0,0 @@
-date,project_id,project_title,user_biography,user_id,user_name,worktime_actual,worktime_monitored,worktime_planned,working_description
-2020-04-01,test2,TEST1,,alice,Alice,4.5,5,6,foo
-2020-04-01,test2,TEST2,,alice,Alice,3,2.5,2,bar
diff --git a/tests/data/labor/detail-worktime.csv b/tests/data/labor/detail-worktime.csv
deleted file mode 100755
index 9edc90db..00000000
--- a/tests/data/labor/detail-worktime.csv
+++ /dev/null
@@ -1,5 +0,0 @@
-date,organization_name,project_title,project_id,username,biography,user_id,worktime_plan_hour,worktime_result_hour,worktime_monitored_hour
-2020-04-01,test,test1,12345678-abcd-1234-abcd-1234abcd5678,Alice,U.K,alice,1,1.2,0.9
-2020-04-01,test,test2,22345678-abcd-1234-abcd-1234abcd5678,Alice,U.K,alice,2,2.4,1.5
-2020-04-02,test,test1,12345678-abcd-1234-abcd-1234abcd5678,Alice,U.K,alice,1,1.2,0.9
-2020-04-01,test,test2,22345678-abcd-1234-abcd-1234abcd5678,Bob,U.S,bob,3,3.6,3.1
diff --git a/tests/data/labor/user.csv b/tests/data/labor/user.csv
deleted file mode 100755
index 827d4fdb..00000000
--- a/tests/data/labor/user.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-user_id,username,biography
-alice,Alice,U.K
-bob,Bob,U.S
-chris,Chris,U.S
diff --git a/tests/data/labor/worktime-per-date-user.csv b/tests/data/labor/worktime-per-date-user.csv
deleted file mode 100644
index b3bb4b8a..00000000
--- a/tests/data/labor/worktime-per-date-user.csv
+++ /dev/null
@@ -1,5 +0,0 @@
-date,user_id,username,biography,worktime_plan_hour,worktime_result_hour,availability_hour
-2020-04-01,alice,Alice,U.K,3,3.6,3
-2020-04-01,bob,Bob,U.S,3,3.6,3.5
-2020-04-02,alice,Alice,U.K,1,1.2,2
-2020-04-02,bob,Bob,U.S,0,0,2.5
diff --git a/tests/test_experimental.py b/tests/test_experimental.py
index d6533db7..1308a1a4 100644
--- a/tests/test_experimental.py
+++ b/tests/test_experimental.py
@@ -1,18 +1,10 @@
 import configparser
-import datetime
-import json
 import os
 from pathlib import Path
 
 import annofabapi
 
 from annofabcli.__main__ import main
-from annofabcli.experimental.dashboard import (
-    PrintDashBoardMain,
-    RemainingTaskCount,
-    get_remaining_task_count_info_from_task_list,
-    get_worktime_for_period,
-)
 
 # プロジェクトトップに移動する
 os.chdir(os.path.dirname(os.path.abspath(__file__)) + "/../")
@@ -34,85 +26,4 @@
 class TestCommandLine:
     command_name = "experimental"
 
-    def test_list_labor_worktime(self):
-        out_file = str(out_dir / "list_labor_worktime.csv")
-        main(
-            [
-                self.command_name,
-                "list_labor_worktime",
-                "--project_id",
-                project_id,
-                "--start_date",
-                "2020-07-01",
-                "--end_date",
-                "2020-07-02",
-                "--output",
-                str(out_file),
-                "--yes",
-            ]
-        )
-
-    def test_list_labor_worktime_from_csv(self):
-        out_file = str(out_dir / "list_labor_worktime.csv")
-        main(
-            [
-                self.command_name,
-                "list_labor_worktime_from_csv",
-                "--csv",
-                str(test_dir / "list_labor_worktime/intermediate.csv"),
-                "--format",
-                "total",
-                "--output",
-                str(out_file),
-            ]
-        )
-
-    def test_dashboad(self):
-        out_file = str(out_dir / "dashboard.csv")
-        main(
-            [
-                self.command_name,
-                "dashboard",
-                "--project_id",
-                project_id,
-                "--date",
-                "2020-07-01",
-                "--output",
-                str(out_file),
-                "--yes",
-            ]
-        )
-
-
-class TestDashboard:
-    @classmethod
-    def setup_class(cls):
-        cls.main_obj = PrintDashBoardMain(service)
-
-    task_list = [
-        {"status_for_summary": "complete", "updated_datetime": "2020-04-01T18:36:11.159+09:00"},
-        {"status_for_summary": "annotation_not_started", "updated_datetime": "2020-04-02T18:36:11.159+09:00"},
-    ]
-
-    def test_get_remaining_task_count_info_from_task_list(self):
-        actual = get_remaining_task_count_info_from_task_list(self.task_list)
-        assert actual == RemainingTaskCount(complete=1, annotation_not_started=1)
-
-    def test_get_worktime_for_period(self):
-        actual_worktime_dict = {
-            "2020-04-01": 1.0,
-            "2020-04-02": 10.5,
-            "2020-04-04": 5.5,
-        }
-        actual = get_worktime_for_period(
-            actual_worktime_dict, lower_date=datetime.date(2020, 4, 2), upper_date=datetime.date(2020, 4, 4)
-        )
-        assert actual == 16.0
-
-    def test_get_task_phase_statistics(self):
-        actual = self.main_obj.get_task_phase_statistics(project_id)
-
-    def test_create_dashboard_values(self):
-        with open(test_dir / "task.json") as f:
-            task_list = json.load(f)
-        actual = self.main_obj.create_dashboard_data(project_id, date="2020-07-01", task_list=task_list)
+    pass
diff --git a/tests/test_labor.py b/tests/test_labor.py
index 47b41edd..3290db98 100644
--- a/tests/test_labor.py
+++ b/tests/test_labor.py
@@ -22,44 +22,6 @@
 
 
 class TestCommandLine:
-    def test_list_worktime_by_user_with_project_id(self):
-        output_dir = str(out_dir / "labor")
-        main(
-            [
-                "labor",
-                "list_worktime_by_user",
-                "--project_id",
-                project_id,
-                "--user_id",
-                service.api.login_user_id,
-                "--start_date",
-                "2019-09-01",
-                "--end_date",
-                "2019-09-01",
-                "--add_availability",
-                "--output_dir",
-                str(output_dir),
-            ]
-        )
-
-    def test_list_worktime_by_user_with_organization_name(self):
-        output_dir = str(out_dir / "labor")
-        main(
-            [
-                "labor",
-                "list_worktime_by_user",
-                "--organization",
-                organization_name,
-                "--user_id",
-                service.api.login_user_id,
-                "--start_date",
-                "2019-09-01",
-                "--end_date",
-                "2019-09-01",
-                "--output_dir",
-                str(output_dir),
-            ]
-        )
 
     def test_list_worktime_with_project_id(self):
         output_file = out_dir / "labor/list_worktime.csv"
diff --git a/tests/test_local_experimental.py b/tests/test_local_experimental.py
index 08cdc6a0..ac958593 100644
--- a/tests/test_local_experimental.py
+++ b/tests/test_local_experimental.py
@@ -3,14 +3,6 @@
 
 import pandas
 
-from annofabcli.experimental.list_labor_worktime import (
-    create_df_with_format_column_list,
-    create_df_with_format_column_list_per_project,
-    create_df_with_format_details,
-    create_df_with_format_total,
-    create_df_with_format_total_by_project,
-    create_df_with_format_total_by_user,
-)
 
 # プロジェクトトップに移動する
 os.chdir(os.path.dirname(os.path.abspath(__file__)) + "/../")
@@ -18,38 +10,3 @@
 data_dir = Path("./tests/data/experimental")
 out_dir = Path("./tests/out/experimental")
 
-
-class TestListLaborWorktime:
-    @classmethod
-    def setup_class(cls):
-        (out_dir / "list_labor_worktime").mkdir(exist_ok=True, parents=True)
-
-    def test_create_df_with_format_details(self):
-        df = pandas.read_csv(str(data_dir / "list_labor_worktime/intermediate.csv"))
-        df2 = create_df_with_format_details(df)
-        df2.to_csv(out_dir / "list_labor_worktime/out-details.csv", index=False)
-
-    def test_create_df_with_format_total_by_user(self):
-        df = pandas.read_csv(str(data_dir / "list_labor_worktime/intermediate.csv"))
-        df2 = create_df_with_format_total_by_user(df)
-        df2.to_csv(out_dir / "list_labor_worktime/out-by_user.csv", index=False)
-
-    def test_create_df_with_total(self):
-        df = pandas.read_csv(str(data_dir / "list_labor_worktime/intermediate.csv"))
-        df2 = create_df_with_format_total(df)
-        df2.to_csv(out_dir / "list_labor_worktime/out-total.csv", index=False)
-
-    def test_create_df_with_format_column_list(self):
-        df = pandas.read_csv(str(data_dir / "list_labor_worktime/intermediate.csv"))
-        df2 = create_df_with_format_column_list(df)
-        df2.to_csv(out_dir / "list_labor_worktime/out-column_list.csv")
-
-    def test_create_df_with_format_column_list_per_project(self):
-        df = pandas.read_csv(str(data_dir / "list_labor_worktime/intermediate.csv"))
-        df2 = create_df_with_format_column_list_per_project(df)
-        df2.to_csv(out_dir / "list_labor_worktime/out-column_list_per_project.csv")
-
-    def test_create_df_with_format_total_by_project(self):
-        df = pandas.read_csv(str(data_dir / "list_labor_worktime/intermediate.csv"))
-        df2 = create_df_with_format_total_by_project(df)
-        df2.to_csv(out_dir / "list_labor_worktime/out-by_project.csv")
diff --git a/tests/test_local_labor.py b/tests/test_local_labor.py
index fce7d3f7..acd221d0 100644
--- a/tests/test_local_labor.py
+++ b/tests/test_local_labor.py
@@ -2,81 +2,8 @@
 
 import pandas
 
-from annofabcli.labor.list_worktime_by_user import LaborAvailability, ListWorktimeByUserMain
 
 out_path = Path("./tests/out/labor")
 data_path = Path("./tests/data/labor")
 (out_path / "labor").mkdir(exist_ok=True, parents=True)
 
-
-class TestListWorktimeByUser:
-    def test_get_first_and_last_date(self):
-        first_date, last_date = ListWorktimeByUserMain.get_first_and_last_date("2019-01")
-        assert first_date == "2019-01-01"
-        assert last_date == "2019-01-31"
-
-    def test_get_first_and_last_date2(self):
-        first_date, last_date = ListWorktimeByUserMain.get_first_and_last_date("2019-02")
-        assert first_date == "2019-02-01"
-        assert last_date == "2019-02-28"
-
-    def test_get_start_and_end_date_from_month(self):
-        start_date, end_date = ListWorktimeByUserMain.get_start_and_end_date_from_month("2019-01", "2019-02")
-        assert start_date == "2019-01-01"
-        assert end_date == "2019-02-28"
-
-    def test_get_start_and_end_date_from_month2(self):
-        start_date, end_date = ListWorktimeByUserMain.get_start_and_end_date_from_month("2019-12", "2020-01")
-        assert start_date == "2019-12-01"
-        assert end_date == "2020-01-31"
-
-    def test_create_worktime_df_per_date_user(self):
-        worktime_df = pandas.read_csv(data_path / "detail-worktime.csv")
-        user_df = pandas.read_csv(data_path / "user.csv")
-        df = ListWorktimeByUserMain.create_worktime_df_per_date_user(worktime_df, user_df=user_df)
-        df.to_csv(out_path / "worktime-per-date-user.csv")
-
-        labor_availability_list_dict = {
-            "alice": [
-                LaborAvailability(
-                    date="2020-04-01", account_id="", user_id="alice", username="Alice", availability_hour=3
-                ),
-                LaborAvailability(
-                    date="2020-04-02", account_id="", user_id="alice", username="Alice", availability_hour=2
-                ),
-            ],
-            "bob": [
-                LaborAvailability(
-                    date="2020-04-01", account_id="", user_id="bob", username="Bob", availability_hour=3.5
-                ),
-                LaborAvailability(
-                    date="2020-04-02", account_id="", user_id="bob", username="Bob", availability_hour=2.5
-                ),
-            ],
-        }
-        df2 = ListWorktimeByUserMain.create_worktime_df_per_date_user(
-            worktime_df, user_df=user_df, labor_availability_list_dict=labor_availability_list_dict
-        )
-        df2.to_csv(out_path / "worktime-per-date-user2.csv")
-
-        # worktime_dfが０件の時
-        df3 = ListWorktimeByUserMain.create_worktime_df_per_date_user(
-            worktime_df=pandas.DataFrame(columns=["date", "user_id", "worktime_plan_hour", "worktime_result_hour"]),
-            user_df=user_df,
-            labor_availability_list_dict=labor_availability_list_dict,
-        )
-        df3.to_csv(out_path / "worktime-per-date-user3.csv")
-
-        # worktime_dfとlabor_availability_list_dictの両方が０件の時
-        df4 = ListWorktimeByUserMain.create_worktime_df_per_date_user(
-            worktime_df=pandas.DataFrame(columns=["date", "user_id", "worktime_plan_hour", "worktime_result_hour"]),
-            user_df=user_df,
-            labor_availability_list_dict=None,
-        )
-        df4.to_csv(out_path / "worktime-per-date-user4.csv")
-
-    def test_create_worktime_df_per_user(self):
-        worktime_df_per_date_user = pandas.read_csv(data_path / "worktime-per-date-user.csv")
-        user_df = pandas.read_csv(data_path / "user.csv")
-        df = ListWorktimeByUserMain.create_worktime_df_per_user(worktime_df_per_date_user, user_df)
-        df.to_csv(out_path / "worktime-per-user.csv")
diff --git a/tests/test_local_statistics.py b/tests/test_local_statistics.py
index bc789d14..3780ec99 100644
--- a/tests/test_local_statistics.py
+++ b/tests/test_local_statistics.py
@@ -337,8 +337,8 @@ def test_get_df_worktime(self):
         ]
 
         member_list = [
-            {"account_id":"alice","user_id": "alice", "username": "Alice", "biography": "U.S."},
-            {"account_id":"bob","user_id": "bob", "username": "Bob", "biography": "Japan"},
+            {"account_id": "alice", "user_id": "alice", "username": "Alice", "biography": "U.S."},
+            {"account_id": "bob", "user_id": "bob", "username": "Bob", "biography": "Japan"},
         ]
         df = get_df_worktime(event_list, member_list)
 
diff --git a/tests/test_statistics.py b/tests/test_statistics.py
index e2dae525..604d6d52 100644
--- a/tests/test_statistics.py
+++ b/tests/test_statistics.py
@@ -50,54 +50,6 @@ def test_list_annotation_count_by_input_data(self):
             ]
         )
 
-    def test_list_by_date_user(self):
-        main(
-            [
-                "statistics",
-                "list_by_date_user",
-                "--project_id",
-                project_id,
-                "--output",
-                str(out_dir / "list_by_date_user-out.csv"),
-            ]
-        )
-
-    def test_list_cumulative_labor_time(self):
-        main(
-            [
-                "statistics",
-                "list_cumulative_labor_time",
-                "--project_id",
-                project_id,
-                "--output",
-                str(out_dir / "list_cumulative_labor_time-out.csv"),
-            ]
-        )
-
-    def test_list_labor_time_per_user(self):
-        main(
-            [
-                "statistics",
-                "list_labor_time_per_user",
-                "--project_id",
-                project_id,
-                "--output",
-                str(out_dir / "list_labor_time_per_user-out.csv"),
-            ]
-        )
-
-    def test_list_task_progress(self):
-        main(
-            [
-                "statistics",
-                "list_task_progress",
-                "--project_id",
-                project_id,
-                "--output",
-                str(out_dir / "task-progress-out.csv"),
-            ]
-        )
-
     def test_summarize_task_count(self):
         main(
             [