SalesForceのデータをPleasanterに連携してみるお話

# はじめに
SalesForceに作成されたレポートを、Pleasanterに登録するお話です。
この記事ではSalesForceのAPIをPleasanterから実行する一連の流れを記載します。
# SalesForce側の準備
今回は、SalesForceのレポートAPIを使ってレポートのデータを取得してPleasanterに登録します。

### SalesForceに必要なデータを準備する
SalesForceに必要なデータを準備します。今回は以下の「商品」のデータを準備しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167316/497c9cc7-df9f-1d66-1d0f-2abef5c8e963.png)
### SalesForceにカスタムレポート、レポート作成する
必要に応じて、SalesForce側のカスタムレポートとレポートを作成します。
作成方法ついて、この記事では割愛します。

:::note info
SalesForceのドキュメント
https://help.salesforce.com/s/articleView?id=sf.reports_custom.htm&language=ja&type=5
https://help.salesforce.com/s/articleView?id=sf.rd_reports_build.htm&type=5
:::

# Pleasanter側の準備

Pleasanter側にSalesForceのデータを投入するためのテーブルを作成しておきましょう。
この記事では、商品名、商品コード、商品説明をすべて分類項目で記録テーブルを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167316/404c3a2a-3dd3-05bd-a012-b17807bc20b4.png)



# SalesForceAPIの実行

### SalesForceのアクセストークンを取得する
アクセストークンを取得します。
アクセストークンの取得には、接続アプリケーションを新規作成して、OAuth2 Client Credentialsフローを使うのがシンプルです。
以下の記事を参考にさせていただきました。
https://qiita.com/shunkosa/items/ec5fab901401c364ee7a

PleasanterのサーバースクリプトのHttpClientを使って取得する場合のサンプルコードは以下となります
```javascript
    // SalesForce接続アプリケーションの設定情報
    const CleiendId = {クライアントID};
    const ClientSecret = {クライアントシークレット};
    const OAuthUrl = 'https://{SalesForceドメイン}/services/oauth2/token';

    let data = {
        grant_type: 'client_credentials',
        client_id: CleiendId,
        client_secret: ClientSecret,
    };

    //HttpClientの設定(SalesForce OAuth認証)
    httpClient.RequestHeaders.Add('User-Agent', 'Pleasanter');
    httpClient.MediaType = 'application/x-www-form-urlencoded';
    httpClient.RequestUri = OAuthUrl;
    httpClient.Content = createParameters(data);
    let responseOAuth = httpClient.Post();

    if(!httpClient.IsSuccess) {
        context.Log('Error: (' + httpClient.StatusCode + ')' + responseOAuth);
    };

    //オブジェクトをURLエンコードしたパラメータ形式に変換する関数
    function createParameters(obj) {
        let result =[];
        for(var key in obj) {
            result.push(encodeURIComponent(key) + '=' +encodeURIComponent(obj[key]));
        }
        return result.join('&');
    }
```

:::note info
Pleasanter公式マニュアル：HttpClientの使い方
https://pleasanter.org/ja/manual/server-script-http-client
:::


### 取得したアクセストークンでSalesForceのレポートAPIを実行する
レポートIDを取得します、レポートIDは、SalesForceでレポートを開いた際のURLに記載されています
```
https://{SalesForceドメイン}/lightning/r/Report/{レポートID}/view?queryScope=userFolders
```

取得したAPIKEYを使ってSalesForceのレポートを取得するサンプルは以下のコードです
バージョンはSalesForceのバージョンに合わせてください

:::note info
SalesForceのバージョン
https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_versions.htm
:::

```javascript
    const ReportUrl = 'https://{SalesForceドメイン}/services/data/{バージョン}/analytics/reports/{レポートID}';

    //HttpClientの設定(SalesForce レポート実行)
    //OAuth認証で取得したアクセストークンをヘッダに追加(Bearerの後は半角スペース必須)
    httpClient.RequestHeaders.Add('Authorization', 'Bearer ' + {アクセストークン}; 
    httpClient.RequestUri = ReportUrl;
    let response = httpClient.Post();
```

実行すると、以下のようなレイアウトでJSONが返却されます。（一部省略）

```json
{
    "attributes": {
        "describeUrl": "/services/data/v61.0/analytics/reports/{レポートID}/describe",
        "instancesUrl": "/services/data/v61.0/analytics/reports/{レポートID}/instances",
        "reportId": "{レポートID}",
        "reportName": "商品レポート_Pleasanter連携用",
        "type": "Report"
    },
    "allData": true,
    "factMap": {
        "T!T": {
            "aggregates": [
                {
                    "label": "2",
                    "value": 2
                }
            ],
            "rows": [
                {
                    "dataCells": [
                        {
                            "label": "りんご",
                            "recordId": "01tF9000004y49jIAA",
                            "value": "01tF9000004y49jIAA"
                        },
                        {
                            "label": "12345",
                            "recordId": "01tF9000004y49jIAA",
                            "value": "12345"
                        },
                        {
                            "escapedLabel": "青森県産",
                            "label": "青森県産",
                            "recordId": "01tF9000004y49jIAA",
                            "value": "青森県産"
                        }
                    ]
                },
                {
                    "dataCells": [
                        {
                            "label": "みかん",
                            "recordId": "01tF9000004y49oIAA",
                            "value": "01tF9000004y49oIAA"
                        },
                        {
                            "label": "45678",
                            "recordId": "01tF9000004y49oIAA",
                            "value": "45678"
                        },
                        {
                            "escapedLabel": "和歌山県産",
                            "label": "和歌山県産",
                            "recordId": "01tF9000004y49oIAA",
                            "value": "和歌山県産"
                        }
                    ]
                }
            ]
        }
    },
```

### Pleasanterにデータを投入する

商品コードをKeyにして、サーバースクリプトのUpsertでデータを登録します。

```javascript
    const ReportUrl = 'https://{SalesForceドメイン}/services/data/{バージョン}/analytics/reports/{レポートID}';

    //HttpClientの設定(SalesForce レポート実行)
    //OAuth認証で取得したアクセストークンをヘッダに追加(Bearerの後は半角スペース必須)
    httpClient.RequestHeaders.Add('Authorization', 'Bearer ' + {アクセストークン}; 
    httpClient.RequestUri = ReportUrl;
    let response = httpClient.Post();

    if(!httpClient.IsSuccess) {
        context.Log('Error: (' + httpClient.StatusCode + ')' + response);
    };

    for(var rec of JSON.parse(response.replace(/!/g,'')).factMap.TT.rows){

        let attendance = {
            Keys: ["ClassA"],
            ClassHash: {
                ClassA: rec.dataCells[1].label,
                ClassB: rec.dataCells[0].label,
                ClassC: rec.dataCells[2].label
            }
        };
        items.Upsert({PleasanterのサイトID}, JSON.stringify(attendance));

    };
```

### Pleasanter側の結果を確認する

Pleasanterにレコードが正しく登録されているか確認します

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167316/0a232519-5e47-eebc-1053-52f7f40cf3ff.png)

# さいごに
サーバースクリプトを使えばAPIの連携が可能です。バックグラウンドサーバースクリプトを使用して、日次など、定期実行してもよいでしょう。
また、サンプルではPleasanterへのレコードの登録を1行ずつ処理していますが、Pleasanter ver.1.4.6.0で実装された、bulkupsertを使えばで一括処理できるので、改善の余地があります。
バックグラウンドサーバースクリプト機能が実装され、単体で外部連携のバッチ処理ができるようになったのはPleasanterの大きな魅力だと思います。
これからもドンドンPleasanterがアップデートされて、便利になっていくのがとても楽しみ！

:::note info
bulkupsert
https://pleasanter.org/ja/manual/api-record-bulkupsert
バックグラウンドサーバースクリプト
https://pleasanter.org/ja/manual/background-server-script
:::