フローを使ってスケジュール済みレポートに似せたメールを送信する

[Flowに関するまとめページに戻る](https://qiita.com/Keiji_otsubo/items/55ebc9c634a3216f3990)

-------------

# はじめに

スケジュール済みレポートのメール送信を利用していますが、大きな制限があります。

+ [ユーザが登録可能なレポート数の上限](https://help.salesforce.com/s/articleView?id=000383344&type=1)
現在、ユーザは**最大 7 つ**のレポートを登録し、設定された条件が満たされるたびに通知を受けることができます。 この上限はハードコーディングされているため、現時点では拡張することはできません。

7レポートまでしか使えないんですよね。


仕方がないので、Apexでコーディングして以下のようなフォーマットでメールを送ることにしています。
現在はスケジュールされたApexより起動していますが、送信先の追加や変更の時にSandBoxで変更して本番環境にデプロイする必要があります。まぁ、少々面倒です。そこでスケジュールされたフローを使えば変更作業が楽になるのではと思って挑戦したいと思います。
ただし、私は普段全くフローを使わない（ウソでした使えない）のでとても苦労しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/84e03708-58b2-2d3e-0aca-f6ebbdb2a536.png)


# 基本的な考え方

1 .今回は自分に関係するレポートだけを抽出したいと思います。　そのため検索に使う値と、送信先を入力パラメータとして渡したいと思います。 このパラメータは「:」で区切った形として、使用する前にApexクラスの中で分割してそれぞれのパラメータとしたいと思います。
2. またできれば、List変数（コレクション変数）で、複数のユーザ分を一括して処理できるようにします。


# さっそく躓きましたね

+ [Apex を呼び出すフロー、コレクション変数を渡すことができません](https://qiita.com/Keiji_otsubo/items/5f9eb4f0598fc911c109)

```
上記に少し書かせていただきましたが、何故かList<String>と書いてもフローではコレクション変数としては認識しませんでした。
なんと、List<List<String>>と書けばコレクション変数として認識できました。何でだろうなぁ。
```

コレクション変数を認識してできたと思いましたが、エラーになります。

:::note alert
結果数は、1 つの一括実行要求で実行されたインタビュー数と一致しません。
:::

同じようにList<String>で**2件**返しているんですが... 
英語のメッセージでは

:::note alert
The number of results does not match the number of interviews that were executed in a single bulk execution request.
:::

数に騙されました。　入力と出力の変数の型が違うからエラーになったようです。変な２個のList型にすると機能しました。


# 実際のコード

```
    @InvocableMethod(label='sendRport')
    public static List<List<String>>  test008(List<List<String>> inputStringList) {      
        List<String> retList = new List<String> ();
        List<List<String>> retList2 = new List<List<String>> ();
        if (inputStringList.size() ==0 ){
            retList.add('0');
            retList2.add(retList);
            return retList2;
        }
        
        for (String Params : inputStringList[0]) {
            List<String> Parm = Params.split(':');
            system.debug(Parm);
            String kyoten = Parm[0];
            Map<String,Object>  inMap = new Map<String,Object>();
            String mySOQL2 = mySOQL + ' AND Eigyousyo__c Like \'' + kyoten +'%\' order by Tantousya__r.Name';
            List<KojiDaicyo2__c> KojiDaicyo2List = Database.query(mySOQL2);
            inMap.put('KojiDaicyo2List',KojiDaicyo2List);
            inMap.put('reportName','★工事台帳:注文書が確認できていません。確認してください。');
            inMap.put('toAddresses' , Parm[1]);
            
            Map<String,Object> RetMap = generateReport3(inMap,true);
            RetMap.put('Size',KojiDaicyo2List.size());        
            
            retList.add(String.valueof(KojiDaicyo2List.size()));
        }
        
        retList2.add(retList);
        return retList2;
        
    }
```

# InvocableMethod 関する考慮事項

ちょうどこの記事を書いている時にInvocableMethodの質問があったので更に調べてみました。
色々と制限があります。
[フローでのApexアクションについて](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000JfQWkSAN)

**実装メモ**

+ 呼び出し可能なメソッドは、static で、public または global である必要があり、そのクラスは外部クラスである必要があります。
+ **クラスの 1 つのメソッドにのみ InvocableMethod アノテーションを付加できます。**
+ **他のアノテーションと InvocableMethod アノテーションを併用することはできません。**

**入力および出力**

最大 1 つの入力パラメータが存在する可能性があり、そのデータ型は次のいずれかである必要があります。

+ プリミティブデータ型のリスト、またはプリミティブデータ型のリストのリスト – 汎用 Object 型はサポートされていません。
sObject 型のリスト、または sObject 型のリストのリスト。
+ 汎用 sObject 型のリスト (List<sObject>)、または汎用 sObject 型のリストのリスト (List<List<sObject>>)。
+ サポートされている型の変数、またはユーザ定義の Apex 型を含み、InvocableVariable アノテーションが付加されているユーザ定義型のリスト。各自のデータ型を実装するカスタムのグローバルまたは公開 Apex クラスを作成し、そのクラスに呼び出し可能な変数アノテーションが付加されているメンバー変数が少なくとも 1 つ含まれていることを確認します。


戻り値の型が Null 以外の場合は、メソッドによって返されるデータ型が次のいずれかである必要があります。

+ プリミティブデータ型のリスト、またはプリミティブデータ型のリストのリスト – 汎用 Object 型はサポートされていません。
sObject 型のリスト、または sObject 型のリストのリスト。
+ 汎用 sObject 型のリスト (List<sObject>)、または汎用 sObject 型のリストのリスト (List<List<sObject>>)。
+ サポートされている型の変数、またはユーザ定義の Apex 型を含み、InvocableVariable アノテーションが付加されているユーザ定義型のリスト。各自のデータ型を実装するカスタムのグローバルまたは公開 Apex クラスを作成し、そのクラスに呼び出し可能な変数アノテーションが付加されているメンバー変数が少なくとも 1 つ含まれていることを確認します。

# @InvocableVariable の使い方

独自のクラスでList型の変数を作る必要があるみたいです。

```
@InvocableMethod(label='sendRport2')
    global static List<ReturnValue>  test006(List<ReturnValue> inputStringList) {
        
        List<ReturnValue> retList = new List<ReturnValue> ();

        return retList;
    }

    global class ReturnValue {
        @InvocableVariable
        global Boolean isSuccess;
        @InvocableVariable
        global String message;
        @InvocableVariable
        global String recordId;
    }
```

それぞれの変数に入力、出力できそう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/23fa9954-2cb1-e7c9-31c4-7611e94efb34.png)


# 参考になる類似の質問

+ [呼び出し可能な Apex アクションが Flow のコレクションを受け入れない](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000NHMNR)
+ [Number of results do not match the number of interviews that have been carried out in a single execution request.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007F3NzU)

:::note
Remember that size of the list you pass to the Apex code should be similar to the size of the list you return to the flow  

https://developer.salesforce.com/forums/?id=906F0000000g0PyIAI
:::