所属会社名義でSalesforceにおけるセキュリティ、及びセキュリティチェックに有用な状態チェック機能についてブログを書きました。
機能面の説明等について、個人的には出来のいい投稿だと思っています。
読んでいただけるとうれしいです。
プロセスビルダーとフローの違い:個人取引先での取引先名の扱い
はじめに
取引先レコードの取引先名(Name)は、通常だと「取引先名」項目の値が設定されますが、個人取引先レコードの場合は取引先責任者の名前(Name)と同様、「(姓)+(半角スペース)+(名)」が設定されます。
ある日「プロセスビルダーで取引先名を変更すればアクションが動作するよう設定したものが、個人取引先レコードで姓or名を変更しても動作しない」という事象が発生しました。
「個人取引先は姓か名を変えれば取引先名も当然変わるからプロセスも動作するだろう」と考えていたのですが、確認したところ確かにそのような動作でした。
また「じゃあフローだとどうなるんだろう」と試したところその後のアクションが動作するという、プロセスビルダーとは異なる動作になりました。
そこで条件を単純化しても同じ動作になるか確認してみました。
確認できた動作
実際に確認したところ、個人取引先においては以下の動作でした。
- プロセスビルダーの場合
- プロセスビルダーで
ISCHANGED([Account].Name)
を条件としてプロセスを作成し、個人取引先の姓or名を編集した場合、「条件を満たさない」と判断されその後のルール適用時のアクションは動作しない。
- プロセスビルダーで
- フローの場合
ISCHANGED({!$Record.Name})
を条件としたフローを作成し、個人取引先の姓or名を編集した場合、「条件を満たす」と判断されその後の処理は継続する。
デバッグログでの確認
上記動作をデバッグログで確認したところ、個人取引先のNameは姓(FirstName)、名(LastName)によらずログ上ではName=null
で固定となっていました。
プロセスビルダーでISCHANGED([Account].Name)
を条件としたプロセスが動作しないのはこのためと考えられます。
一方、フローでも個人取引先のNameがName=null
で固定の動作は変わらないのですが、なぜプロセスビルダーと違いその後の処理が継続するのかは分かりませんでした。
恐らく、フローの内部動作で「個人取引先の場合、{!$Record.Name}
では姓(FirstName)、名(LastName)の値を見る」ようにされているのではないかと思いますが詳細は不明です。
余談
ちなみに取引先責任者の名前(Name)での動作も確認したのですが、以下の通りどちらでも動作しませんでした。
- プロセスビルダー
ISCHANGED([Contact].Name)
を条件に使用したプロセスは有効化できるが、実行時に「myVariable_current.Name の値が設定されていないか、割り当てられていないため、フローでこの値にアクセスできませんでした。」エラーが発生するため実際には動作しない。
- フロー
ISCHANGED({!$Record.Name})
を条件に使用した時点でフローを有効化できない。
おわりに
プロセスビルダーからフローへの移行を求められている昨今、画面だけでなく機能のアップデートも図られていると感じた一件でした。
「同じ条件、アクションならプロセスビルダーもフローも動作は同じ」と思わず、検証を行うのが大事ですね。
個人取引先無効組織でもエラーにならない、Apexで個人取引先有効組織にしかない項目へアクセスする方法
個人取引先無効組織でもエラーにならない、Apexで個人取引先有効組織にしかない項目へアクセスする方法について、zennに記事を投稿しました。
sObject変数から項目を削減するApexコード
sObject変数から項目を削減するApexコードについて、zennに記事を投稿しました。
項目が空白値でも一時停止要素ありのフローを動作させる
注意
この投稿は Known Issues: Pause element in Schedule Triggered Flow not considering Null value for $Record global variable while checking in Decision element の事象が解消していないことを前提としています。
Known Issueが解決済みの場合は本内容で記載した対応は不要と思われますので、一度Known Issueサイトをご確認ください。
はじめに
フローの要素の1つ、一時停止要素。
通常の更新を行うだけならあまり使わない要素ですが、フロー内でコールアウト実行を行う場合は必須の要素となっています。
参考:Salesforceヘルプ: スケジュールトリガーフローに関する考慮事項 より
スケジュールトリガフローは、待機要素を実行した後にのみコールアウトを実行できます。たとえば、待機要素がないと、フローは外部オブジェクトへのアクセス、コールアウトを実行する Apex アクションの実行、または外部サービス登録から生成されたアクションの実行ができません。
この一時停止要素ですが、上述したKnown Issueにより、以下の状況では「$Record.XX__c の値が設定されていないか、割り当てられていないため、フローでこの値にアクセスできませんでした。」というエラーが発生しフローが起動しません。
- 開始要素の「オブジェクト」でレコードを取得している。
- 一時停止要素後に「$Record.XX__c」のように$Record変数の項目値を取得しており、かつ実際のレコードではその項目に空白値が入っている。
この問題はWorkaroundがなく、Salesforceサポートに問い合わせても「回避方法はありませんので、一時停止要素の後に空白値がありえる項目にはアクセスしないでください。」と言われます。
ちなみにこの問題は「空白値へのアクセス」がエラーのトリガーとなるため、 IF(ISBLANK({!$Record.XX__c}), "a", {!$Record.XX__c})
のように空白値の項目にアクセスする数式を使うだけでもエラーになります。
…と言われても「一時停止要素の後には空白値がありえる項目には一切アクセスしない」というのは制約が強すぎて不便極まりないです。
ということで、本エラーを回避する方法を調べました。
エラー回避方法
結論としては単純で、以下を行えばOKです。
- 開始要素の「オブジェクト」でレコードを取得しない。
- 処理に使用するレコードは「レコードの取得」要素で最初に取得し、ループ内で「一時停止→レコード更新内容の割り当て→レコード更新用コレクション変数に追加」を行い、ループ後にレコード更新を行う。
この場合、ループごとに一時停止が行われますが空白値を含む項目にアクセスしてもエラーにはならず、最後まで処理が流れます。
参考になれば幸いです。
カスタムメタデータを用いたApexクラスのテスト方法
カスタムメタデータを用いたApexクラスのテスト方法について、Zennに記事を作成しました。
フローのコンテキストによる動作の違い
はじめに
フローのコンテキストには以下の3つがあります。
- ユーザコンテキスト
- レコードアクセス権は組織の共有設定、ロール階層等によって決まる。(ユーザが見えないレコードはフローでも取得できない)
- 実行ユーザのプロファイルおよび権限セットによって、フローのオブジェクト権限および項目レベルのアクセス権が決まる。
- システムコンテキスト(共有あり)
- レコードアクセス権は組織の共有設定、ロール階層等によって決まる。(ユーザが見えないレコードはフローでも取得できない)
- 実行ユーザのプロファイルおよび権限セットは無視され、フローはシステム権限でアクセス可能な全オブジェクト、全項目にアクセスできる。
- システムコンテキスト(共有なし)
- システム権限でレコードにアクセスする。(ユーザが見えないレコードでもフローで取得可)
- 実行ユーザのプロファイルおよび権限セットは無視され、フローはシステム権限でアクセス可能な全オブジェクト、全項目にアクセスできる。
このフローのコンテキストの動作の違いを明確にする機会がありましたので、実際に動作を調べた結果を書いていきます。
調査
概要
まずは以下の画面フローを作成します。
そして以下の条件それぞれで画面フローを実行し、どのような動作になるかを確認します。
- レコードAをフロー実行ユーザが「見える/見えない」
- レコードBはフロー実行ユーザが「見える」で固定
- 「産業コード」項目をフロー実行ユーザが「読み書き不可/読みのみ可/読み書き可」
- フローコンテキストが「ユーザ/システム(共有あり)/システム(共有なし)」
結果
レコードAが | 「産業コード」項目の アクセス権限 |
コンテキスト | ||
ユーザ | システム(共有あり) | システム(共有なし) | ||
見えない | 読み書き不可 | 項目アクセス不可による レコード取得時エラー |
正常終了するが レコードAの項目値を 取得できないため 空データで更新 |
正常更新 |
見えない | 読みのみ可 | 項目アクセス不可による レコード更新時エラー |
正常終了するが レコードAの項目値を 取得できないため 空データで更新 |
正常更新 |
見えない | 読み書き可 | 正常終了するが レコードAの項目値を 取得できないため 空データで更新 |
正常終了するが レコードAの項目値を 取得できないため 空データで更新 |
正常更新 |
見える | 読み書き不可 | 項目アクセス不可による レコード取得時エラー |
正常更新 | 正常更新 |
見える | 読みのみ可 | 項目アクセス不可による レコード更新時エラー |
正常更新 | 正常更新 |
見える | 読み書き可 | 正常更新 | 正常更新 | 正常更新 |
おまけ
今回の投稿はTrailheadの Secure Application Lifecycle Management Superbadge Unit にて"We can't find the expected running contexts for the 'Product Creation' and 'Price Book Entry Creation' flows"エラーがすぐ解決できなかったことが原因でした。 trailhead.salesforce.com
このエラーは以下のTrailblazer Communityでの投稿でも多くのユーザを悩ませているようです。
Trailblazer Community: Secure Application Lifecycle Management Superbadge Unit
前述の調査結果の通り、ユーザのオブジェクトアクセス・項目アクセス権限を適用する場合はユーザコンテキスト、オブジェクトアクセス・項目アクセス権限を無視したい場合はシステムコンテキストということ、そして権限は必要最低限のものを与える(「共有あり」、「共有なし」どちらでもいいなら「共有あり」を選ぶ)を理解すれば解けます。
私のように「項目アクセスできなくてもフローによる更新が必要?よしシステムコンテキスト(共有なし)を適用だ」という思考ではダメです。
参考資料
フローでApexアクションとして使用するApexの引数指定
フローでApexを要素として使用できることは以前から知っていましたが、フロー⇔Apex間の変数のやり取りを行うためのApex側の型指定について、分かりやすい資料を見つけられなかったので自分用に作成しました。
プレゼン資料:Salesforceの検索動作の話
今の知識をまとめたくなってプレゼン資料を作ったものの、出しどころがなかったのでここで公開します。
(Einstein Searchがない時代の知識で書いたため、現在のEinstein Searchでは合わないところもあるかもしれませんがご了承ください。)
プレゼン資料:Salesforceのインデックスの話
今の知識をまとめたくなってプレゼン資料を作ったものの、出しどころがなかったのでここで公開します。