予測の基礎となるレコード グリッド をカスタマイズする

開発者は、このリファレンス ドキュメントを使用して、イベントとコンテキスト オブジェクトについて学習し、予測の基になるレコード グリッド をカスタマイズします。 コンテキスト オブジェクトを使用すると、グリッド 全体または特定のフィールドを読み取り専用にしたり、フィールドを無効にしたり、エラー通知を表示したりするなどのカスタマイズを実行できます。

ライセンスとロールの要件

要件タイプ 以下が必要です
ライセンス Dynamics 365 Sales Premium または Dynamics 365 Sales Enterprise
詳細情報: Dynamics 365 Sales の価格
セキュリティ ロール システム カスタマイザー
詳細: 営業向けに事前定義されたセキュリティ ロール

Note

このトピックで参照されている予測コンテキスト オブジェクトは、Microsoft Dataverse の実行コンテキストとは異なります。 予測コンテキスト オブジェクトは予測に固有であり、基になるレコード グリッド の高度な構成をサポートします。

基になるレコード グリッドのイベント

予測では、以下のイベントに対応しています:

次のサンプル シナリオは、サポートされているイベント ハンドラーに基づいて作成されています。

OnRowLoad イベント

OnRowLoad イベントは、グリッドに読み込まれたすべての基盤となるレコードに対してトリガーされます。 OnRowLoad イベント ハンドラーに受け渡されるコンテキスト オブジェクトには、基盤となるレコードに固有の API が含まれています。

OnRowLoad ハンドラーを使用して実行できるサンプル シナリオを次に示します。

Note

予測構成の場合、基になるレコード グリッド で Groupby 属性を選択すると、さまざまなエンティティの基になるレコードが表示されます。 これらのエンティティに基づいてロジックを処理するには、エンティティに基づいて常に少数のフィールドのみを有効にするロジックとエンティティに基づくフィールドの編集を無効にするのサンプルを参照してください。

OnChange イベント

OnChange イベントは、基になるレコード グリッド 内のセルの値が更新され、セルがフォーカスされていないときにトリガーされます。

注意

  • 基になるレコード グリッド の場合、フィールドの変更は トリガー OnChange および OnSave イベント ハンドラー(存在する場合)によって実行されます。
  • OnChange ハンドラーでクライアント API を使用してフィールドにエラー通知が設定されている場合、保存はトリガーされません。 予測クライアント API に関する通知については、setNotification context.getFormContext().data.entity.attributes.getByName("Attribute Name").controls.get(0) の API に移動します。
  • OnChange ハンドラーへの属性間のマッピングはなく、フィールドが変更されると、コンテキスト オブジェクト パラメータを使用して OnChange ハンドラーがトリガーされます。 ハンドラーをトリガーした属性を特定するには、属性オブジェクトの getIsDirty 関数を使用します。 詳細: context.getFormContext().data.entity.attributes.getByName("Attribute Name")

OnChange ハンドラーを使用して実行できるサンプル シナリオを次に示します。

OnSave イベント

OnSave イベントは、基になるレコード グリッド のセル内の値が変更され、セルがフォーカスされていないときにトリガーされます。 ただし、OnChange ハンドラーが同じ予測構成に対して存在する場合、OnSave ハンドラーは OnChange ハンドラーの後に呼び出されます。

OnSave ハンドラーは、フィールドを実際に保存する前に呼び出されます。

注意

  • 基になるレコード グリッド の場合、フィールドの変更は トリガー OnChange および OnSave イベント ハンドラー(存在する場合)によって実行されます。
  • OnSave ハンドラーでクライアント API を使用してフィールドにエラー通知が設定されている場合、保存はトリガーされません。 予測クライアント API に関する通知については、setNotification context.getFormContext().data.entity.attributes.getByName("Attribute Name").controls.get(0) の API に移動します。
  • OnSave ハンドラーへの属性間のマッピングはなく、フィールドが変更されると、コンテキスト オブジェクト パラメータを使用して OnSave ハンドラーがトリガーされます。 ハンドラーをトリガーした属性を特定するには、属性オブジェクトの getIsDirty 関数を使用します。 詳細: context.getFormContext().data.entity.attributes.getByName("Attribute Name")

OnSave ハンドラーを使用して実行できるサンプル シナリオを次に示します。

基になるレコードのイベント ハンドラーのコンテキスト オブジェクト グリッド

コンテキスト オブジェクトには、予測内の基盤となるレコードに固有の操作を実行するための一連の API が含まれています。 このコンテキスト オブジェクトは、基になるレコード グリッド ビューのイベント ハンドラーにパラメーターとして渡されます。

次の API がサポートされています。

context.getFormContext メソッド

基になるレコード グリッド 上のレコードへの参照を返します。

context.getFormContext().data.entity

これはエンティティ オブジェクトを返し、次のメソッドがあります。

メソッド 返り値の種類 説明設定
getEntityName() String レコードのエンティティの論理名を表す文字列を返します。
getId() String レコードの GUID 値を表す文字列を返します。
attributes リスト ビューに関連する属性のリストと、基になるレコードの一部として読み込まれるエンティティを返します グリッド。 次の操作を実行できます。
- context.getFormContext().data.entity.attributes.forEach
- context.getFormContext().data.entity.attributes.getByName(arg)
- context.getFormContext().data.entity.attributes.get(index)

context.getFormContext().data.entity.attributes.getByName("Attribute Name")

これは属性オブジェクトを返し、次のメソッドがあります。

メソッド 返り値の種類 説明設定
getName() String 属性の論理名を表す文字列を返します。
getValue() -- 属性のデータ値を取得します。
getIsDirty() ブール型 属性値に対する変更内容が保存されていないことを示すブール値を返します。
controls リスト 各属性オブジェクトのコントロールのリストを返します。
注意: controls オブジェクト リストの長さは常に 1 です。get(0) 直接使用できます。

context.getFormContext().data.entity.attributes.getByName("Attribute Name").controls.get(0)

これは、属性へのコントロール オブジェクト マッピングを返します。次のメソッドがあります。

メソッド 返り値の種類 説明設定
getDisabled() ブール型 コントロールが無効かどうかを返します。
setDisabled(bool) -- コントロールに無効な値 (有効または無効) を設定します。
setNotification(message: string, uniqueId?: string) ブール型 データが無効であることを示すコントロールのエラー メッセージを表示します。 このメソッドを使用すると、セル内のコントロールの横に赤の十字アイコンが表示されます。 エラー アイコンにカーソルを合わせると、指定されたメッセージが表示されます。 エラー アイコンを選択すると、行が再読み込みされ、変更が元に戻されます。 uniqueId は、clearNotification メソッドの使用時にこのメッセージをクリアするために使用されます。
clearNotification(uniqueId?: string) ブール型 既にコントロールに表示されているメッセージを削除します。 一意の ID が指定されていない場合、そのコントロールのすべての通知が削除されます。

Note

JavaScript ファイルの関数名は、イベント名と一致し、コンテキスト オブジェクト パラメーターを受け取ることをお勧めします。

例 1:

基になるレコード グリッド のすべてのフィールドを読み取り専用にするJavaScriptコードを作成しましょう。 また、グリッドが正常にロードおよび保存されると、各行に対して OnRowLoad 関数を呼び出します。

function OnRowLoad(executionContext) {
    // Iterating through all attributes and disabling it.
    executionContext.getFormContext().data.entity.attributes.forEach(
        attribute => {
            attribute.controls.get(0).setDisabled(true);
        }
    )
}

例 2:

営業案件 エンティティのみのいくつかを除くすべてのフィールドを無効にする JavaScript コードを作成しましょう。 また、グリッドが正常にロードおよび保存されると、各行に対して OnRowLoad 関数を呼び出します。

function OnRowLoad(executionContext) {

    // Get the logical name of the loaded entity as part of underlying records grid.
    var entityName = executionContext.getFormContext().data.entity.getEntityName();

    if (entityName === "opportunity") {

        // Defining the attributes list from opportunity that has to be enabled if loaded as part of view.
        var OPTY_ENABLE_ATTRS_LIST = ["name", "msdyn_forecastcategory", "actualvalue", "actualclosedate", "estimatedvalue", "estimatedclosedate"];

        executionContext.getFormContext().data.entity.attributes.forEach(
            attribute => {
                // Disabling all attributes other than OPTY_ENABLE_ATTRS_LIST
                if (!OPTY_ENABLE_ATTRS_LIST.includes(attribute.getName())) {
                    attribute.controls.get(0).setDisabled(true);
                }
            }
        )        
    }
}

例 3:

読み込まれた予測構成のさまざまなエンティティを処理する JavaScript コードを作成しましょう。

営業案件エンティティの場合、スクリプトは以下を無効にします。

  • 名前列
  • actualRevenue および actualCloseData (forecastCategory の値が最良のケース、コミット、省略、またはパイプラインの場合)。
  • estimatedRevenue および estimatedCloseDate (forecastCategory の値が受注または失注の場合)。

同様に、スクリプトは取引先企業エンティティの名前列を無効にし、他のエンティティのすべての列を無効にします。

また、グリッドが正常にロードおよび保存されると、各行に対して OnRowLoad 関数を呼び出します。


function OnRowLoad(executionContext) {
		 
    // Get the logical name of the loaded entity as part of underlying records grid.
    var entityName = executionContext.getFormContext().data.entity.getEntityName();
    
    // If loaded logical name of entity in underlying records grid is opportunity.
    if (entityName === "opportunity") {
        
       var allAttrs = executionContext.getFormContext().data.entity.attributes;

       // Disable column name for all records if exists in the view.
       var nameAttr = allAttrs.getByName("name");
       if (nameAttr) {
           nameAttr.controls.get(0).setDisabled(true);
       }

       var fcatAttr = allAttrs.getByName("msdyn_forecastcategory");
       if (fcatAttr) {
           // Disable actualRevenue, actualCloseDate for forecastcategory Bestcase, committed, omitted, or pipeline.
           if (fcatAttr.getValue() <= 100000004 && fcatAttr.getValue() >= 100000001) {
                   var actualRevenueAttr = allAttrs.getByName("actualvalue");
                   var actualCloseDateAttr = allAttrs.getByName("actualclosedate");
                   if (actualRevenueAttr) actualRevenueAttr.controls.get(0).setDisabled(true);
                   if (actualCloseDateAttr) actualCloseDateAttr.controls.get(0).setDisabled(true);
           }
           // Disable estimatedRevenue, estimatedCloseDate for forecastCategory won or lost.
           else if (fcatAttr.getValue() == 100000005 || fcatAttr.getValue() == 100000006) {
                   var estimatedRevenueAttr = allAttrs.getByName("estimatedvalue");
                   var estimatedCloseDateAttr = allAttrs.getByName("estimatedclosedate");
                   if (estimatedRevenueAttr) estimatedRevenueAttr.controls.get(0).setDisabled(true);
                   if (estimatedCloseDateAttr) estimatedCloseDateAttr.controls.get(0).setDisabled(true);
           }
       }
   } 
   
   // Else disable name column, if loaded logical name of entity is Account.
   else if (entityName === "account"){
       var attrNameObj = executionContext.getFormContext().data.entity.attributes.getByName("name");
       if (attrNameObj) {
               attrNameObj.controls.get(0).setDisabled(true);
       }
   } 
   
   // For all other entities
   else {
       executionContext.getFormContext().data.entity.attributes.forEach(
           attribute => {
               attribute.controls.get(0).setDisabled(true);
           }
       )
   }
}

例 4:

値が 10 未満の場合に保存をブロックし、売上見込み列にエラー通知を表示する検証 JavaScript ファイルを作成しましょう。 また、エラー通知を削除し、売上見込み列の値が 10 以上に修正されたときに保存できるようにします。 ここで、 OnChange 関数は、予測の基礎となるレコード グリッド で任意のフィールドの値が更新されたときに呼び出されます。


// OnChange function is invoked when any field's value is updated on the underlying records grid of the forecast
function OnChange(executionContext) {

    let entity = executionContext.getFormContext().data.entity;

    // Verify the logical name of the entity and load as part of the underlying records grid.
    if (entity.getEntityName() === "opportunity") {

        // Verify estimated revenue value
        let estValAttr = entity.attributes.get("estimatedvalue");

        // Verify if this attribute exists within the grid view and changed
        if(estValAttr && estValAttr.getIsDirty()) 
        {
            if(estValAttr.getValue() < 10){

                // This will show an error icon next to the estimated revenue field. On hovering over the icon, the below provided message is displayed.
                // Any save attempts are blocked by the system until all notifications are cleared from the columns.
                estValAttr.controls.get(0).setNotification("Estimated revenue cannot be less than 10");
            }
            else{
                // Clearing notifications to save.
                estValAttr.controls.get(0).clearNotification();
            }
        }
    }
}

context.getWebApiContext()

これは webApiContext オブジェクトを返し、次のメソッドがあります。

メソッド 説明設定
retrieveRecord(entityLogicalName, id, options)
then (successCallback, errorCallback);
エンティティ レコードを取得します。 詳細: retrieveRecord (クライアント API 参照)
updateRecord(entityLogicalName, id, data)
then(successCallback, errorCallback);
エンティティ レコードを更新します。 詳細: updateRecord (クライアント API 参照)
createRecord(entityLogicalName, data)
then(successCallback, errorCallback);
エンティティ レコードを作成します。 詳細: createRecord (クライアント API 参照)
deleteRecord(entityLogicalName, id)
then(successCallback, errorCallback);
エンティティ レコードを削除します。 詳細: deleteRecord (クライアント API 参照)

context.getEventArgs().preventDefault()

preventDefault() メソッドは、OnSave イベント内で使用可能です。 OnSave 内でこのメソッドを呼び出すと、保存イベントが進行しなくなります。

例:

サンプル JavaScript を作成して営業案件グリッドを開き、自動保存イベントをブロックして、売上見込み値が 10 未満の場合にウィンドウ アラートを開きます。 また、売上見込み値が 10 以上の場合、自動保存イベントを許可します。

// OnSave function will be invoked whenever grid attempts to save changes made to any field. 
function OnSave(executionContext){

    let entity = executionContext.getFormContext().data.entity;

    // Verify the logical name of the entity and load as part of the underlying records grid.
    if (entity.getEntityName() === "opportunity") {

        // Verify estimated revenue value
        var estValAttr = entity.attributes.get("estimatedvalue");

        if(estValAttr && estValAttr.getIsDirty() && estValAttr.getValue() < 10){

            // This call will prevent the save event from proceeding
            executionContext.getEventArgs().preventDefault(); 
            alert("Estimated revenue cannot be less than 10");

        }
    }
}

基礎となるレコードをカスタマイズする グリッド