本稿は Salesforce アーキテクト の視点から執筆されています。
背景と適用シナリオ
Salesforce プラットフォームにおいて、ビジネスプロセスの自動化は生産性向上と業務標準化の鍵となります。その中でも、Approval Process (承認プロセス) は、レコードの承認を体系的かつ自動的に管理するための標準機能であり、極めて重要な役割を担います。割引申請、経費精算、休暇申請、契約書のレビューなど、組織内のあらゆる階層で発生する承認ワークフローを Salesforce 上で実現します。
Salesforce アーキテクトとして私たちが考慮すべきは、「いつ、どのように承認プロセスを利用するのが最適か」という設計上の問いです。例えば、単純なステータス変更であれば Flow (フロー) で十分かもしれません。しかし、以下のような要件が明確に存在する場合、承認プロセスは最適な選択肢となります。
- 明確な承認階層: 申請者のマネージャー、そのまた上長といった、固定または動的な複数ステップの承認者が必要なケース。
- レコードのロック: 承認プロセスが進行中のレコードを編集不可にし、データの整合性を担保する必要があるケース。
- 承認履歴の追跡: いつ、誰が、どのようなコメントと共に承認または却下したか、という監査証跡を標準オブジェクトで管理したいケース。
- 委任と再割り当て: 承認者が不在の場合に、代理承認者に権限を委任したり、管理者が手動で承認者を変更したりする必要があるケース。
アーキテクトの視点からは、承認プロセスを単なる自動化ツールの一つとして捉えるのではなく、組織のガバナンス、データ整合性、そしてユーザーエクスペリエンスを支える基盤アーキテクチャの一部として設計することが求められます。
原理説明
Salesforce の承認プロセスは、一連のステップで構成されるステートマシンとして機能します。レコードが特定の条件を満たしたときにプロセスが開始され、最終的に承認または却下されるまで、定義されたルートをたどります。その主要な構成要素を理解することは、堅牢な設計の第一歩です。
1. Process Start (プロセス開始条件)
レコードが承認プロセスに入るための入口です。数式を用いて「割引率が 15% を超えた場合」や「契約金額が 100 万円以上の場合」といった複雑な条件を定義できます。この条件が満たされたレコードのみが、承認申請の対象となります。
2. Initial Submission Actions (申請時のアクション)
ユーザーがレコードを承認申請した直後に実行されるアクションです。例えば、レコードのステータスを「申請中」に変更したり、関係者にメールアラートを送信したりします。重要な点として、この時点で Record Locking (レコードロック) が発生し、承認者が明示的に許可しない限り、申請者(一部例外を除く)や他のユーザーはレコードを編集できなくなります。
3. Approval Steps (承認ステップ)
承認プロセスの核となる部分です。各ステップでは以下の項目を定義します。
- Step Criteria: このステップに入るための追加条件。「全レコードを対象とする」か、あるいは「契約金額が 500 万円以上の場合のみ、この役員承認ステップに進む」といった条件分岐が可能です。
- Assign to Approver: 承認者を指定します。申請者のマネージャー、特定のロール、公開グループ、キュー、あるいは特定のユーザーなど、柔軟に指定できます。アーキテクチャの観点からは、個人ではなく Queue (キュー) や Role (ロール) を指定することで、人事異動などに対するプロセスの耐性を高めることができます。
- Rejection Behavior: 承認者が却下した場合の挙動を定義します。前のステップに戻すか、プロセス全体を終了(最終却下)するかを選択できます。
4. Final Actions (最終アクション)
全ての承認ステップが完了した後の最終的な処理を定義します。
- Final Approval Actions (最終承認時のアクション): レコードのステータスを「承認済み」に変更する、外部システムにデータを連携するためのアウトバウンドメッセージを送信する、といった処理を実行します。
- Final Rejection Actions (最終却下時のアクション): レコードのステータスを「却下」に変更し、申請者に却下理由を通知するメールを送信する、といった処理を実行します。
- Recall Actions (申請取り消し時のアクション): 申請者が承認申請を取り消した際に実行されるアクション。ステータスを元に戻すなどの処理を行います。
これらのコンポーネントを組み合わせることで、複雑なビジネス要件に対応した承認フローを宣言的に構築できます。アーキテクトは、これらの要素がビジネスルールとどのようにマッピングされるかを正確に把握し、スケーラブルでメンテナンス性の高い設計を心がける必要があります。
示例代码
承認プロセスは主に画面設定で構築しますが、Apex を使用してレコードを承認申請することも可能です。これにより、カスタム UI (LWC や Visualforce) からの申請や、バッチ処理による一括申請など、より高度な自動化が実現できます。以下は、Salesforce の公式ドキュメントで提供されている `Approval` クラスを使用したサンプルコードです。
この例では、特定の商談 (Opportunity) レコードを承認申請しています。
// 新しい商談レコードを作成し、承認申請の準備をします
Opportunity opp = new Opportunity(Name='Test Opportunity',
StageName='Prospecting',
CloseDate=System.today().addMonths(1),
Amount=50000);
insert opp;
// Approval.ProcessSubmitRequest オブジェクトを作成して、
// 申請に関する詳細情報を設定します
Approval.ProcessSubmitRequest req = new Approval.ProcessSubmitRequest();
// コメントを設定します。これは承認履歴に表示されます。
req.setComments('Submitting request for approval.');
// 承認申請するレコードの ID を設定します。
req.setObjectId(opp.Id);
// 承認者を指定することも可能です(任意)。
// この例では、現在のユーザーが次の承認者として設定されます。
// これにより、動的な承認者割り当てが可能になります。
// req.setNextApproverIds(new Id[] {UserInfo.getUserId()});
// スキップすることも可能です(任意)。
// req.setSkipEntryCriteria(true);
// 申請を実行します
try {
Approval.ProcessResult result = Approval.process(req);
// プロセスの結果を確認します
if (result.isSuccess()) {
System.debug('Submitted for approval successfully: ' + result.getInstanceId());
} else {
// エラーハンドリング
for (Approval.ProcessResult.Error error : result.getErrors()) {
System.debug('Error submitting for approval: ' + error.getMessage());
}
}
} catch (System.DmlException e) {
System.debug('An unexpected error has occurred: ' + e.getMessage());
}
コードの解説:
- `Approval.ProcessSubmitRequest` オブジェクト: 承認申請に必要な情報(対象レコードID、コメント、次の承認者など)を格納するためのリクエストオブジェクトです。
- `req.setObjectId(opp.Id)`: どのレコードを承認プロセスにかけるかを指定する、最も重要な部分です。
- `Approval.process(req)`: この静的メソッドが、実際に承認プロセスを開始します。これは DML 操作と見なされ、Governor Limits (ガバナ制限) の対象となります。
- `result.isSuccess()`: 処理が成功したかどうかを返す boolean 値です。成功した場合、`result.getInstanceId()` で承認プロセスインスタンスの ID を取得できます。
- エラーハンドリング: `try-catch` ブロックと `result.getErrors()` を使用して、申請が失敗した場合(例: 開始条件を満たしていない、有効な承認プロセスがない)のエラーを適切に処理することが、堅牢なアプリケーション設計には不可欠です。
注意事項
承認プロセスの設計と実装においては、アーキテクトとして特に以下の点に注意を払う必要があります。
1. 権限とセキュリティ
承認申請や承認・却下の操作には、適切な権限が必要です。プロファイルや権限セットで「承認申請」のシステム権限が付与されているか、また、承認者が対象レコードへの参照アクセス権を持っているかを確認する必要があります。Apex から申請する場合、実行コンテキスト(User Mode か System Mode か)が権限にどう影響するかを理解しておくことが重要です。`Approval.process()` はユーザーコンテキストで実行されるため、実行ユーザーの権限が適用されます。
2. ガバナ制限とパフォーマンス
承認プロセスのアクション(項目自動更新、メール送信など)は、トリガーやフローと同様に、トランザクション内の DML 操作や SOQL クエリの制限に影響を与えます。特に、項目自動更新がトリガーを再帰的に呼び出す可能性があるため、意図しないガバナ制限超過に繋がることがあります。アーキテクトは、オブジェクト全体の自動化設計(トリガー、フロー、承認プロセス)を俯瞰し、実行順序と相互作用を考慮する必要があります。
3. レコードロックの副作用
承認プロセス中のレコードロックはデータの整合性を保つ上で強力な機能ですが、副作用も伴います。他のユーザーや自動化プロセス(バッチ処理など)がそのレコードを更新しようとすると、`UNABLE_TO_LOCK_ROW` エラーが発生します。特に、長時間にわたる承認プロセスや、API 経由での頻繁なデータ更新が想定されるオブジェクトにおいては、ロックがボトルネックとならないか、慎重に評価する必要があります。
4. メンテナンス性と複雑性
宣言的ツールであるとはいえ、承認プロセスは非常に複雑になり得ます。ステップ数が多く、分岐条件が入り組んでいるプロセスは、変更やデバッグが困難になります。ビジネス要件が非常に動的で、ロジックが複雑な場合は、承認プロセスと Flow を組み合わせたり、あるいは完全に Flow でカスタム承認ロジックを構築したりする方が、長期的なメンテナンス性に優れる場合があります。このトレードオフを判断するのがアーキテクトの重要な役割です。
5. 承認者の無効化
承認者として指定されたユーザーが無効化された場合、そのステップでプロセスは停滞し、エラーとなります。これを避けるため、可能な限り個人ではなくキューを承認者として指定するか、管理者が承認者を再割り当てできる運用フローを確立しておくべきです。
まとめとベストプラクティス
Salesforce の承認プロセスは、構造化された承認ワークフローを実装するための強力な標準機能です。アーキテクトとしてこの機能を最大限に活用するためには、その仕組みと制約を深く理解し、より大きなシステム設計の中に適切に位置づける必要があります。
以下に、アーキテクトが遵守すべきベストプラクティスをまとめます。
- 適切なツールの選択: 要件を精査し、承認プロセスが本当に最適か、Flow や Apex によるカスタム実装と比較検討してください。レコードロックや承認履歴が不要であれば、Flow の方が柔軟性が高い場合があります。
- 承認者の抽象化: 可能な限り、ユーザー個人ではなく、キュー、ロール、または公開グループを承認者として指定します。これにより、組織変更に対するプロセスの回復力が高まります。
- シンプルさの維持: 1つの承認プロセスにロジックを詰め込みすぎないでください。複雑な場合は、複数のプロセスに分割するか、Flow などの他のツールとの連携を検討します。
- 全体的な自動化の考慮: 承認プロセスは、トリガー、Flow、入力規則など、オブジェクト上の他の自動化と連携して動作します。設計時には、これらの実行順序と相互作用を必ず考慮し、意図しない副作用を防ぎます。
- 徹底的なテスト: 正常系だけでなく、却下、取り消し、承認者の不在、レコードロックの競合といった異常系のシナリオも網羅的にテストしてください。
- ドキュメントの整備: 承認プロセスのロジック、各ステップの条件、アクション、承認者の決定方法などを明確にドキュメント化し、将来のメンテナンスに備えます。
これらの原則に従うことで、単に機能するだけでなく、スケーラブルで、メンテナンス性が高く、ビジネスの変化に柔軟に対応できる堅牢な承認アーキテクチャを構築することができるでしょう。
コメント
コメントを投稿