TableauとSalesforceを繋いでみた

# はじめに
ABEMAの広告局のDXチームにて手広くエンジニアをやっている今井です
この記事は、メディア事業部の広告横軸組織PTAのアドベントカレンダー16日目の記事となります

広告局では営業管理にSalesforceを導入しており、私はその導入から定着、促進を現在進行形で携わっており日々Salesforce管理者として勤しんでおります
そこでの苦労話もあるのですがここでは更なる利活用の中でTableauとの連携をおこなったのでそのお話を書かせて頂きます


# やりたいこと
## 課題
組織課題として**月毎の粗利を迅速に把握したい**というのがあります
これは弊社の広告商品は番組内で配信される広告のみではなく番組タイアップやオリジナルCMといったCMを作成する商品があり、これらには番組制作費、キャスティング費といった費用が掛かっております
それらはSalesforceとは別に管理、運用されており**売上と費用の紐付けは人力**による作業となっているので手間と時間が掛かっておりました

## 解決
課題を解決させるために取り組みを始めて
- Salesforceの商談管理に費用を紐付ける
  仕組みを構築した
- 上記のデータを月毎に可視化する
  これからやる

という状態でデータの可視化についてTableauを使用していきます


# オブジェクト構成
前提として以下のオブジェクトを用意して売上と費用を管理するようにしております

| オブジェクト名 | 目的 | 参照先 | データ型 | 多重度 |
| -- | -- | -- | -- | -- |
| Project__c | 商談と費用を束ねる上位概念 | - | - | - |
| Opportunity | 商談管理 | Project__c | 参照関係 | 1対多 |
| ProjectCost__c | 費用 | Project__c | 主従関係 | 1対多 |

上記のオブジェクト構成によりProject__cを介することで売上と費用とを結びつけるとこができます
ただ、この構成の問題点としてOpportunityとProjectCost__cとを対象月で結ぼうとした時そこには関係性がないのでSalesforce標準のレポートでは結合することができず**月毎の売上、費用を集計して粗利を算出する事ができません**
なのでこの問題を解決するための手段としてTableauを用いる事としました



# やったこと
## データに接続
安直にTableauを開きワークブックを新規に作成、そこで接続先のデータとしてSalesforceを選択しました

![スクリーンショット 2022-12-01 13.02.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/ea5bf97d-a1ed-1fdd-ea05-6bc359a28edc.png)

そこからSalesforceのログイン画面に遷移するのかなと勝手に期待していたのですが
```
Custom OAuth is not configured for this datasource. Learn more. (errorCode=170001)
```
とエラーになりここで**Tableau Serverに対して何かしらSalesforceに関する設定が必要**と認識しました

そこでTableau Serverの管理者へ連絡を取りSalesforceと繋げたい旨を伝えて必要な作業について確認を行いそれぞれ進めるととなりました

### Salesfroce
Tableau Serverとの受け口となる接続アプリケーションを作成、OAuthの設定を行う

基本的な流れは[公式のヘルプ](https://help.tableau.com/current/server-linux/ja-jp/config_oauth_sfdc.htm#%E3%82%B9%E3%83%86%E3%83%83%E3%83%971-salesforce-%E3%81%AB%E6%8E%A5%E7%B6%9A%E3%81%95%E3%82%8C%E3%81%9F%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B)をご参照頂きたくここでは要所要所挙げさせていただきます

- 新規接続アプリケーションの作成
  - API (OAuth 設定の有効化)
    - OAuth 設定の有効化
      TRUE
    - コールバック URL
      ```
      https://{Tableau Serverのドメイン}/auth/add_oauth_token
      ```
    - 選択した OAuth 範囲
      - ID URL サービスにアクセス (id, profile, email, address, phone)
      - API を使用してユーザデータを管理 (api)
      - いつでも要求を実行 (refresh_token, offline_access)
- 鍵情報
  作成したアプリケーションの**コンシューマの詳細を管理**ボタンを押します
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/080f5556-f6cb-a615-472b-60592e93439d.png)


  鍵の情報が書かれたページが開きここにあるコンシューマ鍵=クライアントID、コンシューマの秘密=クライアントシークレットになります
  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/f3bddb71-a7a1-056c-8038-9a4b8b6fc13f.png)

### Tableau
Salesforceにて作成したOAuthクライアントの設定をTableauにしていきます
こちらの作業は**サーバー管理者**ロールが必要で私は**Creator**でしたので管理者の方に情報を連携して以下のように進めました

Creatorにはないのですがサイト管理者には画面左側のメニューの中に**設定**がありこちらから行えるようです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/ff252431-8098-f96a-0d82-e33e72efa4c1.png)

Salesforceにて作成した接続アプリケーションの鍵情報を連携して設定してもらいました
- クライアントID
  接続アプリケーションのコンシューマ鍵
- クライアントシークレット
  接続アプリケーションのコンシューマの秘密
- リダイレクトURL
  Tableau ServerのURL
  ```
  https://{Tableau Serverのドメイン}/auth/add_oauth_token
  ```

## 接続
改めてTableauを開きワークブックを新規に作成、そこで接続先のデータとしてSalesforceを選択しました
![スクリーンショット 2022-12-01 13.02.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/ea5bf97d-a1ed-1fdd-ea05-6bc359a28edc.png)

Salesforceのログイン画面に遷移するので自身のアカウント、パスワードを設定してログインします

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/ab93a546-c897-75f3-eb52-6fb2669e33eb.png)

ログインしますとアクセス許可の画面に遷移するので許可ボタンを押します

![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/58b05c1d-ea96-a2a1-332d-1ea568e1f715.png)

Salesforceに接続されて各オブジェクトを参照できるようになります

![image (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/8560b3e2-6ea6-3bce-ac1a-41ad876874dd.png)

## データの集計
ここで元々やりたかった参照関係のないオブジェクトを繋いだ集計をしようと当たり障りのないクエリを実行したところ

![スクリーンショット 2022-12-05 12.51.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/53bf6b27-fa57-dbc7-78fa-b357bdb85518.png)

と、エラーを返され何故なのか悩みに悩んだ所ここで求められているのは**SQLではなくSOQL**ではないかと結論に至りました
なので当初考えていたSQLを使った力技で集計しようとしていた計画は断念して**オブジェクト間のリレーションとSOQLの制約に最大限寄り添い**つつ目的を達成するために必要な結合を駆使して集計することとなりました
また、OpportunityとProjectCost__cとをUNION ALLして必要となる月を出すサブクエリはTableau内ではなくSalesforce内に**ProjectTerm__c** というオブジェクトを用意してレコードトリガーフローにてこれを作成することで賄う事としました

| オブジェクト名 | 目的 | 参照先 | データ型 | 多重度 |
| -- | -- | -- | -- | -- |
| ProjectTerm__c | Project毎に商談と費用が発生している月 | Project__c | 主従関係 | 1対多 |


![スクリーンショット 2022-12-05 13.07.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/9c5ae106-6a6a-f4a9-6293-a3046d537154.png)

このデータソースを作ることで案件毎の売上、費用、粗利率に加えてこれを月別にも割り出せるよになるのでより細かい把握が可能になるので異常値の早期発見、早期の措置が可能になる仕組みが整いました

Tableauワークシートイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/960906/b9ba5de0-5442-5db5-fb02-0cfbdceff0d6.png)


# まとめ
今回は**月毎の粗利を迅速に把握したい**との課題から
- Salesforceの商談管理に費用を紐付ける
- 上記のデータを月毎に可視化する

を実現していくにあたりSalesforceでできること、できないこと、得意なこと、苦手なことを鑑みて**持てる選択肢をどの様に使えば望む結果を得られるか、さらには効果を最大化できるか**を考えてプロジェクトを進めました
現在は仕組みを作り動き始めた所なのでまだ定量的成果は出たとは言えませんがこれをしっかりと機能させれば大きな成果を作れるはずなのでその一歩を踏み出せることができたと考えております

このように組織課題を咀嚼しその解決方法を考え、それを遂行していくといった一連の流れをリードさせて頂きまた一つ成長できたと思います
来年はより良い記事を書けるよう頑張っていきます！良いお年を


# 参考
https://help.tableau.com/current/server-linux/ja-jp/config_oauth_sfdc.htm#%E3%82%B5%E3%82%A4%E3%83%88%E3%81%AE%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0-oauth-%E3%81%AE%E6%A7%8B%E6%88%90
https://help.tableau.com/current/server-linux/ja-jp/users_site_roles.htm