Trello × Toggl × GASでタスク管理・工数管理をラクにする

![小見出しを追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/204642d7-41fa-e49f-dd96-f85900c408aa.png)

## はじめに
GASを今まで触ったことがなかったのですが、「せっかくアドカレもあることだし。。。」と思い、初めて触ってみました！**今回はTrello・TogglとGASを使ってよりタスク管理・工数管理をラクにする方法について書いています。**前半は、Trello中心の説明になっていますが、後半で実際にGASを用いたコードも載せています。

## 目次
- Trello
    - リスト構成
    - おすすめChrome拡張機能
    - Power-Up・Butler
- Trello + GAS
    - カード作成を自動化
- Toggl + GAS
    - 工数管理表にその日作業した工数時間を自動で入力させる
- 参考資料

## Trello
### リスト構成

| リスト名 | 内容 |
|:-----------|:------------|
| **Fixed** | ボードについての説明などや週ごとの振り返りなど |
| **Backlog**| いつかやる全てのタスクを放り込んでおくリスト |
| **Tasks（1 week）** | 今週1週間で終えるべきタスクリスト |
| **Tasks（1 day）** | 本日中に終えるべきタスクリスト |
| **Done（1 week）** | 今週1週間で終えたタスクリスト |
| **Done（All）**| 今までに終えた全てのタスクリスト |
| **Repeat** | 繰り返しのタスクリスト |
| **Memo**| 雑多なメモ |

### おすすめChrome拡張機能
Trelloに関するChrome拡張機能としては以下のものを利用しています。

![next_step_for_trello.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/4fe1305c-17ff-1a97-72c4-6652f1e64f6f.png)

**[Next Step for Trello](https://chrome.google.com/webstore/detail/next-step-for-trello/iajhmklhilkjgabejjemfbhmclgnmamf)**：デフォルトでは隠れているチェックリストをカードを開かずとも確認できる。

![scrum_for_trello.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/e4a985f0-f953-9aa8-7ff9-a9998ea376b4.png)

**[Scrum for Trello](https://chrome.google.com/webstore/detail/scrum-for-trello/jdbcdblgjdpmfninkoogcfpnkjmndgje)**：カードに推定作業時間と実質作業時間を追加して工数管理ができる。各タスクに工数を入力しておくことで、後から同じようなタスクを行う際に前回どれくらいの時間がかかったかを把握できるように。

![toggl_track.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/197bacea-018b-4a4e-7af3-b694bea2440f.png)

**[Toggl Track](https://chrome.google.com/webstore/detail/toggl-track-productivity/oejgccbfbmkkpaidnkphaiaecficdnfn?hl=ja)**：どのタスクにどれくらいの時間がかかったのかを[Toggl](https://toggl.com/)に記録できる（事前にTrelloとTogglを連携させる必要あり）

また **「[Trello for Gmail](https://gsuite.google.com/marketplace/app/trello_for_gmail/710372432947?hl=ja)」**も入れています。こちらはGmailの拡張機能でメールのタスク化が楽にできるようになります。

### Power-Up・Butler
Trelloには**Power-Up**と**Butler**という機能があります。

**Power-Up**はTrelloのボードをより使いやすくしてくれる機能です。無料会員の場合使える数に制限があります。**Butler**はTrelloに組み込まれているワークフローを自動化してくれる機能ですが、こちらも無料会員の場合、使用できる回数や数に制限があります。
以下が実際に使っている**Power-Up**と**Butler**です。

**Power-Up**

- [Custom Fields](https://trello.com/power-ups/56d5e249a98895a9797bebb9)

![custom_field.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/8cd7195d-acde-b5fa-79db-69ed005f4812.png)

Custom Fieldsを使うことによって、チェックボックスや日付、ドロップダウンリスト、数字フィールド、テキストフィールドを自由に追加することができます。私は「進捗」「優先度」「着手日」を新規フィールドとして追加しています。

**Butler**

![butler.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/48907f00-3386-8c3e-8e1a-3cdb9916fd43.png)

`when the due date is marked as complete in a card by anyone, move the card to the top of list "🎉 Done（1 week）"`

期限にチェックを入れると自動的にDone（1 week）リストの一番上に移動させるようにしています。

## Trello + GAS
では、実際にTrelloとGASを連携させてより便利に使えるようにしていきます！
事前に、GASで用意されている **プロパティストア** にTrelloのキーやトークンなどを格納しておきます。

```javascript
let scriptProperties = PropertiesService.getScriptProperties();
const TRELLO_KEY   = scriptProperties.getProperty('TRELLO_KEY');
const TRELLO_TOKEN = scriptProperties.getProperty('TRELLO_TOKEN');
const USER_NAME = scriptProperties.getProperty('USER_NAME');
const BOARD_ID = scriptProperties.getProperty('BOARD_ID');
const TASKS_LIST_ID = scriptProperties.getProperty('TASKS_LIST_ID');
const REPEAT_LIST_ID = scriptProperties.getProperty('REPEAT_LIST_ID');
```

### カード作成を自動化
![trello_gas03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/0fe8b2bd-035e-d248-9782-43be6d21776c.png)

今回作成したのは、毎日の繰り返しタスクを毎日指定の時間に自動で作成するスクリプトです。TrelloにもCard Repeaterという繰り返しタスクを設定できるPower-Upがあるのですが、無料会員の場合利用できるPower-Upが1つまで（2020/12/03 現在）なのでGASでスクリプトを書きました。

```javascript
// Repeatリストにある毎日行うタスクカードをTaskリストにコピーする
function copyRepeatListDailyTaskToTaskList() {
  let listUrl = 'https://trello.com/1/lists/' + REPEAT_LIST_ID + '/cards?key=' + TRELLO_KEY + '&token=' + TRELLO_TOKEN + '&fields=name';
  // Repeatリストにあるカード情報を取得
  let cardOfRepeatList = UrlFetchApp.fetch(listUrl, { 'method' : 'get' });
  cardOfRepeatList = JSON.parse(cardOfRepeatList.getContentText());
  
  cardOfRepeatList.forEach (function(key) {
    // 指定のカードの場合、そのカードをTaskリストにコピーする
    if (key['id'] === 'xxxxxxxxxxxxxx') {
      let createCardUrl = 'https://api.trello.com/1/cards?key=' + TRELLO_KEY + '&token=' + TRELLO_TOKEN + '&idList=' + TASKS_LIST_ID;
      
      let payload = {
        'pos' : 'top',
        'idCardSource' : key['id']
      };
  
      let option = {
        'method' : 'POST',
        'payload' : payload
      };
      
      UrlFetchApp.fetch(createCardUrl, option);
    }
  });
}

// 毎日指定の時間帯にcopyRepeatListDailyTaskToTaskListを実行
function setCopyRepeatListDailyTaskToTaskListTrigger() {
  let date = new Date();
  // AM9時にセット
  date.setHours(9,0,0,0); 
  ScriptApp.newTrigger('copyRepeatListDailyTaskToTaskList').timeBased().at(date).create();
}
```

### Toggl＋GAS
![flow_chart.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/68ad93e3-3192-ff9f-7ad8-ed302e346b24.png)

#### 工数管理表にその日作業した工数時間を自動で入力させる
例えば以下のような工数管理表があった場合、その日にTogglで計測した各プロジェクトごとの工数時間を記入してくれるスクリプトです。

![kousuukannri_test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298333/5651b714-55e2-f9b8-dab7-e0017994b003.png)

```javascript
let date = new Date();

// 工数管理票に工数を書き込む
function writeToConstructionScheduleControlChart() {
  let spreadSheet = SpreadsheetApp.openById('xxxxxxxxxxxxxxxxxxxxx').getSheetByName('シート1');
  
  // Togglから各プロジェクトの工数時間取得
  let togglReports = getTogglReports();
  
  // Togglに当日のレポート情報がある場合
  if (Object.keys(togglReports).length > 0) {
      let num = date.getDate();
      
      for (var key in togglReports){
        if (key === 'プロジェクトA') {
          spreadSheet.getRange('A2').offset(0, num).setValue(togglReports[key]);
        } else if (key === 'プロジェクトB') {
          spreadSheet.getRange('A3').offset(0, num).setValue(togglReports[key]);
        } else if (key === 'プロジェクトC') {
          spreadSheet.getRange('A4').offset(0, num).setValue(togglReports[key]);
        }
      }
  }
}

//プロジェクトごとの工数を取得
function getTogglReports() {
  let today = Utilities.formatDate(date, 'Asia/Tokyo', "yyyy-MM-dd'T'HH:mm:ss'+09:00'");
  
  let summaryUrl = 'https://api.track.toggl.com/reports/api/v2/summary?user_agent=' + TOGGL_EMAIL + '&workspace_id=' + TOGGL_WORKSPACE_ID + '&since=' + today + '&until=' + today;
  let reports = UrlFetchApp.fetch(summaryUrl, {
                  'method' : 'GET',
                  'headers' : {'Authorization' : 'Basic ' + Utilities.base64Encode(TOGGL_API_TOKEN + ':api_token')}, 
                  'muteHttpExceptions' : true,
                });
  reports = JSON.parse(reports.getContentText());
  
  let todayReports = [];

  for (let i = 0; i < reports['data'].length; i++) {
    if (reports['data'][i].id === xxxxxxxx) { // プロジェクトA
      todayReports['プロジェクトA'] = calcTime(reports['data'][i].time);
    } else if (reports['data'][i].id === xxxxxxxx) { // プロジェクトB
      todayReports['プロジェクトB'] = calcTime(reports['data'][i].time);    
    } else if (reports['data'][i].id === xxxxxxxx) { // プロジェクトC
      todayReports['プロジェクトC'] = calcTime(reports['data'][i].time);  
    }
  }

  return todayReports;
}

// 毎日指定の時間帯にwriteToConstructionScheduleControlChartを実行
function setwriteToConstructionScheduleControlChartTrigger() {
  // PM20時にセット
  date.setHours(20,0,0,0); 
  ScriptApp.newTrigger('writeToConstructionScheduleControlChart').timeBased().at(date).create();
}
```

## 参考資料
- [The Trello REST API](https://developer.atlassian.com/cloud/trello/rest/)
- [GitHub - toggl/toggl_api_docs: Documentation for the Toggl API](https://github.com/toggl/toggl_api_docs)
- [Reference overview | Apps Script | Google Developers](https://developers.google.com/apps-script/reference)