【Salesforce】画面フローからApexバッチを起動する 



初めまして。
Salesforce歴2年の、エンジニアにも片足突っ込んでいるシステム管理者です。
IT業界未経験から今の会社でSalesforceと出会い、いつの間にか2年経ちました。その間に少しずつですが知識も経験も溜まってきました。
せっかくなので備忘録もかねてSalesforceのちょっとした小ネタや苦労したことなどを記録していこうと思います。

## 1.はじめに
今回のテーマはタイトルのとおり、画面フローからApexバッチを起動する方法についてです。

###ターゲット
- Apexは書いたことあるけれどVisualforceは未履修もしくは苦手意識がある人
- ローコードで実装したい開発者
- 既存のフローに既存のバッチを組み込みたい！

###想定ケース
お客様や会社の偉い人からこういう事を言われたことはありませんか？

**「月末に稼働してるバッチ、好きなタイミングでも動かしたいんだけど」**

Apexバッチを手動実行する方法はいくつかありますが、システム管理者ユーザ以外がバッチを呼び出すために画面を作る必要があります。

VisualforceやLWCでの実装が嫌すぎて床で大の字になりながら思いました。
**これ、フローで実装できるのでは？**

## 2.開発環境
Lightning Experience(以下LEX。今回はレコードアクションからフローを実行(後述)するため対象はLEXになります)

## 3.なぜフローなのか：画面フローのいいところ
**UIがLEXと相性がいい**
フローで実装した理由の半分くらいはここにあります。標準機能なので使用感がほかのレコード作成などのアクションと似たUIで実装できます。
VisualforceでもSLDSを使ったり、Lightnngコンポーネントで実装したりと開発でもUIを寄せることは可能ですが、今回の規模であればフローが工数を考えても現実的でした。

**入力規則も含めてノーコードで柔軟に作れる**
フローは2021年3月現在、直近のいくつかのリリースで大きくアップデートされています。
私がフローと初めて出会ったとき（まだ古いフロービルダーの時代です）と比べて実装がかなり簡単かつ柔軟になりました。
入力規則も数式で実装できるため、コードはかけないけど数式なら何とか…というシステム管理者の心強い味方になりつつあります。

**コード実行エラー用の画面も簡単に追加できる**
あまり複雑な分岐やエラーパターンがない時はとても簡単。

## 4.実装

### フロー
今回はレコードのアクションから呼び出す仕様を想定しています。
入力した年度をバッチに渡し、バッチの実行結果を画面に表示するシンプルなフローです。

実装したフローはこんな感じです。
![フロー画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556951/fb9f8741-1740-3b62-1488-40878eed8a93.png)
これはデモなのでほとんど分岐がありませんが、実際にリリースしたものはもう少し細かく分岐を入れています。
フロー側の機能は以下です。

- 入力規則・・・年度を入力するので、半角数字4文字以外の形式ではエラーになるようにしています。
- 実行結果を表示・・・フローとバッチをつなぐクラスの中で、バッチの実行結果をフラグでフローに出力しています。

フローでApexを呼び出すときはフローアクションを使います。こんな感じです。
![Apexアクション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556951/d957cefb-e958-5d97-543b-5d1e4f6f7e8d.png)
このinputYearがフロー用のクラスに値を渡す入力値になります。

フロー用クラスからの出力結果はこんな感じで使えます。変数は指定しなくても自動で設定してくれます（手動設定も可能です）
![出力変数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556951/a8a0a6f6-718a-7994-ac9f-b25210e4f74b.png)

### Apex
フローからApexを呼び出すときはアノテーションを使用します。

- アクション用
 @InvocableMethod(label='アクション名')<br>
 このアクション名はフローアクションの名前になるので分かりやすいものを付けます。
- 変数用
@InvocableVariable(required=true)<br>
後ろのrequired=trueはフローアクション側で変数を必須にするかどうか決定します。trueで必須になります。

変数は入力変数、出力変数ともに内部クラス（サブクラス）の形で実装し、やり取りは全てList型で行います。
つまり、たとえ値が必ず1つしかない時でも、渡すときもリストで渡し、返り値もリストです。

####入力変数

```

public class RecordListInfo {
    @InvocableVariable(required=true)
        public String inputYear;
}
```

####出力変数

```
public class result {
    // バッチ実行の期首日　成功画面で出力用
    @InvocableVariable
    public Date targetDate;
    //バッチが成功したか
    @InvocableVariable
    public Boolean success;
}
```
####フローアクション

```
@InvocableMethod(label='call batch')
public static List<result> callBatch(List<RecordListInfo> targetYears){
    
    List<result> results = new List<result>();
         String resultYear = targetyears[0].inputYear;
         FiscalYearSettings fy = [SELECT Name, StartDate FROM FiscalYearSettings WHERE Name = :resultYear LIMIT 1];

        System.debug('inputYear='+ targetYear);
        try {
            //　バッチを実行
            //　何らかのバッチをここで実行しています。
            
            // 実行結果を取得(バッチから出力結果を渡す）
            //　出力変数に値を設定
            result r = new result();
            r.targetDate = fy.StartDate;
            r.success = true;
            results.add(r);
        } catch (Exception e) {
            // 例外処理　何らかの理由で実行が失敗したらフラグをfalseにする。
            System.debug(e);
            result r = new result();
            r.success = false;
            results.add(r);
        }
    
    // フローに渡す出力値たち
    return results;
}
```

#### 実行結果
Apexアクションから渡された結果をもとに遷移する画面が変わります。
フローはVメッセージのフォントやサイズ、カラーを簡単にカスタムできるのがとても素敵。

- 成功
![処理成功.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556951/09ea4975-6028-d3cc-b357-120386610ec7.png)


- 失敗
![処理失敗.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556951/3df80a5a-2e87-237c-d709-9ad877f7f9af.png)

## 5.終わりに
Salesforceは開発を行えばほとんど何でもできるほど柔軟な実装が可能です。
そんな中でフローも含めた標準機能を使うのか、それとも開発するのかの判断は様々な観点があると思います。
あまりにも複雑な分岐や細かいチェックが必要な時はフローはあまりメンテナンス性がいいとは言えません。
そんなときはVisualforce+コントローラの実装が向いていると思います。
また、フローアクションはLEX限定だったりリストビューアクションで使えなかったりと、要件次第では不向きのこともあります。

ただVisualforceとコントローラの書き方を覚える時間がない、今すぐ実装したい（知識はApexのみ）というニッチな需要もあるかと思いまとめました。
またほかにも、極力標準機能を使いたいノーコードローコード志向の方（余談ですがスケジュールバッチもフローで実装できます）、
フローは最近使っていないけど何ができるのか気になっているという方、
よろしければご参考ください。


参考

[フローで Apex アクションを実行](https://help.salesforce.com/articleView?id=sf.flow_build_extend_apex.htm&type=5)
2021/12/20　修正
for文のなかでSOQLを回すコードになっていたので修正しました