背景と応用シナリオ
Salesforce Field Service(旧Field Service Lightning)は、現場作業員の活動を管理し、最適化するための包括的なソリューションです。保守、修理、設置などの現場サービス業務において、作業員の派遣、スケジュールの最適化、作業報告、在庫管理などを一元的に行うことができます。これにより、顧客満足度の向上、初回解決率の改善、運用コストの削減を実現します。
典型的な応用シナリオとして、通信会社の顧客宅へのインターネット回線設置作業が挙げられます。顧客からの申し込みがあると、Salesforce 上で Work Order (作業指示) が作成されます。この Work Order には、作業内容、必要なスキル(例:光ファイバー敷設技術)、必要な部品、顧客の住所などの情報が含まれます。次に、この Work Order に紐づく Service Appointment (サービス予定) が作成され、適切なスキルを持ち、顧客の所在地に最も近い Service Resource (サービスリソース、つまり現場作業員) に割り当てる必要があります。
しかし、多くの企業ではこのスケジュール作成と派遣(Dispatch)プロセスを手動で行っています。ディスパッチャーは、複数の作業員の現在地、スキル、スケジュール、移動時間を考慮しながら、最適な割り当てを判断しなければならず、これは非常に複雑で時間のかかる作業です。特に、緊急の作業依頼が入った場合や、予定がキャンセルされた場合の再調整は大きな負担となります。
このような課題を解決するため、Salesforce Field Service は強力なスケジュール最適化エンジンを提供していますが、特定のビジネスロジックに基づいてこのプロセスを完全に自動化したいというニーズも高まっています。例えば、「特定の顧客種別の Work Order が作成されたら、即座に最適な作業員を自動で割り当てる」といったシナリオです。本記事では、Apex (Salesforce 独自のプログラミング言語) を使用して、このスケジュールプロセスをプログラムで制御し、高度な自動化を実現する方法について、技術的な観点から詳しく解説します。
原理説明
Field Service のスケジュール自動化を Apex で実現する中心的な役割を担うのが、FSL.ScheduleService
クラスです。この Apex クラスは、Field Service のスケジュールエンジンへのインターフェースを提供し、開発者が Service Appointment のスケジュール、再スケジュール、ピンどめ(固定)、固定解除といった操作をコードから実行できるようにします。
このサービスを利用する際の主要な登場オブジェクトと概念は以下の通りです。
主要オブジェクト
- Work Order (作業指示): 実行されるべき作業を定義するオブジェクトです。作業内容、場所、必要なスキルや部品などを管理します。
- Service Appointment (サービス予定): Work Order に関連付けられ、特定の時間枠で実行される具体的な訪問予定です。スケジュールと派遣の対象となります。
- Service Resource (サービスリソース): 現場で作業を行う個人またはチームです。スキル、稼働時間、サービステリトリーのメンバーシップなどの情報を持っています。
- Service Territory (サービステリトリー): サービスが提供される地理的なエリアです。Service Resource は特定のテリトリーに割り当てられます。
- Skill (スキル): Service Resource が持つ専門技術や資格を表します。Work Order には必要なスキル(Skill Requirement)が定義され、マッチングに使用されます。
スケジュールの心臓部:Scheduling Policy
FSL.ScheduleService
を利用する上で最も重要な概念が Scheduling Policy (スケジュールポリシー) です。これは、スケジュールエンジンが「最適なスロット」をどのように判断するかを定義するルールの集合体です。Scheduling Policy には以下の要素が含まれます。
- Work Rules (作業ルール): スケジュールにおける「制約条件」を定義します。例えば、「Required Skills(必須スキル)」ルールは、Service Appointment に必要なスキルを Service Resource が持っていることを強制します。「Match Territory(テリトリーの一致)」ルールは、Service Appointment と Service Resource の Service Territory が一致することを要求します。これらのルールに違反する候補スロットは、スケジュールの対象から除外されます。
- Service Objectives (サービス目標): スケジュールにおける「評価基準」を定義します。複数の候補スロットが Work Rules を満たす場合に、どのスロットがより「良い」かを点数付けするための基準です。例えば、「Minimize Travel(移動時間を最小化)」や「Preferred Resource(優先リソース)」などがあり、各目標に重みを設定することで、ビジネスの優先順位を反映させることができます。
Apex から FSL.ScheduleService
を呼び出す際には、どの Scheduling Policy を使用するかを指定します。これにより、手動でディスパッチャーがコンソールから操作する際と同じロジックを、コードで再現・自動化することが可能になります。
具体的な Apex の処理フローは、一般的に以下のようになります。
- 自動化のトリガー(例:Work Order の作成)を定義します。
- トリガー内で、スケジュール対象となる Service Appointment の ID を収集します。
FSL.ScheduleService.schedule
メソッドを呼び出します。引数として、Service Appointment の ID リスト、使用する Scheduling Policy の ID、およびその他のオプション(例:スケジュールの日時範囲)を渡します。- メソッドの戻り値である
FSL.ScheduleService.ScheduleResult
を受け取り、スケジュールの成否を確認し、失敗した場合はエラーメッセージを処理します。
示例コード
以下は、新しい Work Order が作成された際に、関連する Service Appointment を自動的にスケジュールする Apex トリガーの例です。このコードは Salesforce の公式ドキュメントで提供されているパターンに基づいています。
この例では、Work Order が作成された後(after insert)、非同期処理(@future)を呼び出してスケジューリングを実行します。これは、スケジューリング処理が時間がかかる可能性があり、Governor Limits (ガバナ制限) に抵触するのを避けるためのベストプラクティスです。
// WorkOrder オブジェクトに対するトリガー trigger WorkOrderTrigger on WorkOrder (after insert) { // スケジュール対象の Service Appointment の ID を格納するリスト List<Id> saIdsToSchedule = new List<Id>(); // 作成された Work Order に紐づく Service Appointment を検索 for(ServiceAppointment sa : [SELECT Id FROM ServiceAppointment WHERE ParentRecordId IN :Trigger.newMap.keySet()]) { saIdsToSchedule.add(sa.Id); } // スケジュール対象の予定が1つ以上存在する場合 if(!saIdsToSchedule.isEmpty()){ // 非同期メソッドを呼び出してスケジューリングを実行 // これにより、トリガーのコンテキストから処理を分離し、ガバナ制限を回避する FSL.ScheduleService.scheduleAppointments(saIdsToSchedule); } } // 非同期処理を担うクラス public class ScheduleAppointments { // @future アノテーションにより、このメソッドが非同期で実行されることを示す @future public static void scheduleAppointments(List<Id> saIds) { // 使用する Scheduling Policy の名前を定義 // 事前に組織で設定されているポリシー名を指定する必要がある String schedulingPolicyName = 'Default'; Id policyId; // SOQL を使用して Scheduling Policy の ID を取得 try { policyId = [SELECT Id FROM FSL__Scheduling_Policy__c WHERE Name = :schedulingPolicyName LIMIT 1].Id; } catch (QueryException e) { // ポリシーが見つからない場合はエラーを記録し、処理を中断 System.debug('Error: Scheduling Policy not found - ' + e.getMessage()); return; } // FSL.ScheduleService.schedule メソッドを呼び出す // 第1引数: Service Appointment の ID のリスト // 第2引数: Scheduling Policy の ID // 第3引数: null の場合、デフォルトのスケジュールモード(通常は ASAP)が使用される // 第4引数: 完了後にデータベースにコミットするかどうかのフラグ List<FSL.ScheduleService.ScheduleResult> scheduleResults = FSL.ScheduleService.schedule(saIds, policyId, null, true); // スケジュール結果をループで確認 for (FSL.ScheduleService.ScheduleResult sr : scheduleResults) { if (sr.isSuccess()) { // 成功した場合のログ出力 System.debug('Successfully scheduled Service Appointment ' + sr.getServiceAppointmentId()); } else { // 失敗した場合のエラー情報を取得してログ出力 List<FSL.ScheduleService.SchedulingError> errors = sr.getErrors(); for(FSL.ScheduleService.SchedulingError error : errors){ System.debug('Error scheduling SA ' + sr.getServiceAppointmentId() + ': ' + error.getMessage()); } } } } }
コードの解説
- トリガー (WorkOrderTrigger): Work Order が作成された直後に実行されます。関連する Service Appointment の ID をすべて収集し、非同期メソッド
scheduleAppointments
に渡します。 - 非同期メソッド (@future):
@future
アノテーションにより、このメソッドは Salesforce のキューに入れられ、リソースが利用可能になった時点で実行されます。これにより、トリガーのトランザクションから切り離され、より高いガバナ制限内で動作します。 - Scheduling Policy の取得: コード内で Scheduling Policy 名をハードコーディングし、SOQL でその ID を取得しています。本番環境では、カスタムメタデータやカスタム設定を使用して、この名前を管理可能にすることが推奨されます。
FSL.ScheduleService.schedule
の呼び出し: このメソッドがスケジューリング実行の核です。成功したかどうかは、戻り値のScheduleResult
オブジェクトのisSuccess()
メソッドで確認できます。- エラーハンドリング: スケジュールに失敗した場合、
getErrors()
メソッドでエラーの詳細(例:「適切なスキルを持つリソースが見つかりません」など)を取得できます。これらのエラーをログに記録したり、管理者に通知したりする処理を実装することが重要です。
注意事項
Apex を使用して Field Service のスケジュールを自動化する際には、以下の点に注意する必要があります。
権限 (Permissions)
Apex コードを実行するユーザーには、Field Service の操作に必要な権限が付与されている必要があります。具体的には、`FSL Admin`、`FSL Dispatcher`、または同等の権限を持つカスタムプロファイル/権限セットが必要です。また、Work Order、Service Appointment、Service Resource などの関連オブジェクトに対する作成、読み取り、更新、削除(CRUD)権限も適切に設定されている必要があります。
API 制限とガバナ制限 (API Limits and Governor Limits)
Field Service のスケジューリングは、内部的に複雑な計算を行っており、Salesforce の標準的なガバナ制限に影響を与える可能性があります。
- CPU 時間制限: 大量の Service Appointment を一度にスケジュールしようとすると、CPU 時間制限に達する可能性があります。非同期処理(
@future
,Queueable
,Batch Apex
)を活用して、処理を小さなチャンクに分割することが不可欠です。 - SOQL/DML 制限: トリガー内で SOQL クエリや DML ステートメントを発行する際は、必ず一括処理(Bulkification)を意識してください。ループ内でクエリや DML を実行することは避けるべきです。
- Field Service 固有の制限: Field Service 自体にも、一度のトランザクションで処理できる予定の数などに内部的な制限が存在する場合があります。大量のデータを扱う場合は、小規模なバッチでテストを行い、パフォーマンスを検証することが重要です。
エラー処理 (Error Handling)
スケジュールが常に成功するとは限りません。適切な Service Resource がいない、稼働時間外である、Work Rules に違反するなど、さまざまな理由で失敗する可能性があります。FSL.ScheduleService.ScheduleResult
を用いて、各 Service Appointment のスケジュール成否を確実にチェックし、失敗した場合はその原因をログに記録する堅牢なエラー処理メカニズムを実装してください。失敗した予定を再処理するためのキューイングメカニズムを検討することも有効です。
データモデルの整合性
スケジュールエンジンの品質は、入力されるデータの品質に大きく依存します。Service Resource のスキル、稼働時間(Operating Hours)、Service Territory のメンバーシップ、移動時間計算のための住所情報などが正確に設定されていることが、自動スケジュールの成功の鍵となります。データが不完全または不正確な場合、エンジンは最適な結果を返すことができません。
まとめとベストプラクティス
Salesforce Field Service のスケジュールプロセスを Apex で自動化することは、運用効率を劇的に向上させ、ディスパッチャーの負担を軽減し、より迅速な顧客対応を可能にする強力な手段です。FSL.ScheduleService
クラスを活用することで、ビジネス固有の要件に合わせた柔軟な自動化ロジックを実装できます。
以下に、実装におけるベストプラクティスをまとめます。
- 非同期処理の徹底: スケジューリングのようなリソースを消費する処理は、必ず
@future
,Queueable
, またはBatch Apex
を使用して非同期で実行し、ガバナ制限の超過リスクを最小限に抑えます。 - 設定の外部化: Scheduling Policy の名前やその他の設定値をコードにハードコーディングするのではなく、カスタムメタデータ型やカスタム設定に格納することで、管理者がコードを修正することなく設定を変更できるようにします。
- きめ細やかなエラーハンドリングとロギング: スケジュールの成否を監視し、失敗した際には詳細なエラーログを記録します。これにより、問題の特定と解決が迅速に行えます。可能であれば、失敗した予定を管理者に通知する仕組みを構築します。
- テストの徹底: Sandbox 環境で、本番に近いデータ量と多様なシナリオ(例:リソースが不足している、スキルがマッチしない、祝日を挟むなど)を用いて、自動化ロジックを十分にテストします。
- Scheduling Policy の活用: 複雑なビジネスルールを Apex コードで実装しようとせず、可能な限り Scheduling Policy の Work Rules と Service Objectives を活用してください。これにより、ロジックの可視性が高まり、メンテナンスが容易になります。Apex はあくまで、そのポリシーを「いつ」「どの予定に対して」実行するかを制御する役割に徹するのが理想的です。
これらのベストプラクティスに従うことで、Salesforce Field Service の能力を最大限に引き出し、スケーラブルで保守性の高い自動化ソリューションを構築することができるでしょう。
コメント
コメントを投稿