プリザンターのサーバスクリプトを用いて、各レコードに対応するユーザーに対して重複なくメールを送信する方法

# はじめに

プリザンターのサーバスクリプトを用いて、各レコードに対応するユーザーに対して重複なくメールを送信する方法をこの記事ではご紹介します。

# 設定

あるテーブル(=管理テーブル)に複数のレコードが存在し、各レコードの「ClassC」にはそのレコードを管理するユーザー(=管理者ID)が設定されています。そして、一覧画面でプロセスで追加したボタン(=実行ボタン)をクリックすることで管理者に対して一斉通知しようと思います。さらに、複数レコードを対象としたとき、管理者が重複しないように重複を排除して、1人の管理者に対して1通のメールが送付されるようにします。  
下記に設定を箇条書きにしました。

* レコードの「ClassC」に管理者が設定されている
* 管理者に対して一斉に通知する
* 複数レコードを対象としたとき、管理者が重複することがある
* 管理者が重複する場合、重複をなくし管理者 : 送付数 = 1 : 1 の関係で送信する

# サーバースクリプト

今回実施したい内容を実現するにあたり、サーバースクリプトがどのように実行されるのかを知っておく必要があります。この後の説明で解明されますが、ここでは1レコードを読み込んだ時にサーバスクリプトが1度実行されます。そして、次のレコードを読み込んだ時また一からサーバースクリプトを実行します。つまり、レコード数に応じてサーバスクリプトが実行されるという仕組みなのです。そうすると、変数をためていくことができず、使いまわすことができません。なぜなら、レコードごとに新しくサーバスクリプトが実行されるのですから。

# ソースコード

### サーバースクリプト1

※条件を更新後に設定してください。

```JavaScript
if (context.ControlId === 'BulkProcessCommand') {
    // クラスC(= サイト管理者のID)を取得
    let address = model.ClassC;
    // context.UserData.Addressesが空だった時の処理
    if (!context.UserData.Addresses) {
        // 初期値としてaddressの値を設定
        context.UserData.Addresses = address;
    } else {
        // addressの値をカンマ区切りで文字列結合
        context.UserData.Addresses += ',' + address;
    }
}
```

### サーバスクリプト2

※条件を画面表示の前に設定してください。

```JavaScript
// 一覧画面にて
// BulkProcessCommand(= 実行)ボタンがクリックされたときの処理
// アカウント管理者にメールを送信する処理
if (context.ControlId === 'BulkProcessCommand') {
    // プロセス：棚卸依頼が選択されている場合
    if (context.Forms.Item.get('BulkProcessingItems') === '1') {
        // 配列を宣言
        let addresses = new Array();
        // 保持していたcontext.UserDataをカンマ区切りで配列に設定
        let results = context.UserData.Addresses.split(',');
        // 配列として設定されているresultsを重複排除して設定
        addresses = Array.from(new Set(results));
        for (let address of addresses) {
            let notification2 = notifications.New();
            // アドレスにサイト管理者IDを設定
            notification2.Address = '[User' + address + ']';
            // タイトルを設定
            notification2.Title = '【Pleasanter】【利用アカウント棚卸】利用アカウントの棚卸をお願いします。';
            // 内容を設定
            notification2.Body = 'アカウント管理者は下記URLより利用アカウントの棚卸を実施してください。\nhttp://pleasanter-dev01.gamma.hm.jp.honda.com/items/25922/index';
            // メールを送信
            notification2.Send();
        }
    }
}
```

# 解説

サーバスクリプト1はレコードを更新した後に動くサーバスクリプトです。そして、サーバスクリプト2は全てのレコードを更新しきった後に実行されるサーバスクリプトです。そして、変数「context.UserData.Addresses」はサーバースクリプト間で共有できる変数です。  
以上を前提として、下記のレコードをもとに解説します。  
サーバスクリプト1はテスト1のレコードを更新する際に呼び出され、更新後テスト2のレコードを更新する際に新たに呼び出されます。一つのサーバスクリプトで実現しようとすると、最後に管理者IDを重複なくまとめてメールを送信することができません。このままではレコードを読み込むごとにメールが送られてしまい、重複を削除することができません。そのため、最後にまとめて重複を排除したユーザーに対してメールを送信するサーバースクリプト2を実装します。しかし、変数はサーバスクリプト内で完結するため、サーバスクリプトをまたいだ変数の共有はできません。そこで、「context.UserData.Addresses」を使います。「context.UserData.Addresses」はサーバースクリプト間で共有できる変数です。そのため、サーバスクリプト1で「context.UserData.Addresses」に管理者IDをためていき、サーバスクリプト2で「context.UserData.Addresses」を使って、メールを一斉送信するという方法で実現しています。厳密には、「context.UserData」がサーバスクリプト間で共有できる領域です。今回は、「context.UserData」という領域に「Addresses」という任意の変数を設定しました。

 # 工夫
「context.UserData.Addresses」という変数は追記しようとしても、追記されることはなく代入されるだけのようでした。そのため、管理者IDを文字列結合させて蓄積させるという方法をとりました。ここでポイントなのはカンマ区切りで文字列結合しているという点です。これによって、サーバスクリプト2のsplit関数でカンマを境に配列を作成しています。これによって、管理者IDを蓄積させ、重複ありの配列を作ることができました。そのうえで、重複した配列を重複をなくした配列にしています。これら一連の実装によって重複なくメールを送信することができるようになりました。

 # さいごに
今回は既存の知識から工夫で実現した内容になります。今までは知らないことを含んでいましたが、今回は今まで培った知識を使った応用編という位置づけになります。これらの内容が誰かの役に立つとよいです。