メモ
コミュニティの関心グループが Yammer から Microsoft Viva Engage に移行されました。 Viva Engage コミュニティに参加し、最新のディスカッションに参加するには、「 Finance and Operations Viva Engage Community へのアクセスを要求する 」フォームに入力し、参加するコミュニティを選択します。
この記事では、最適化アドバイザーのための新しいルールを作成する方法について説明します。 例えば、見積依頼 (RFQ) のケースに空のタイトルがあるかどうかを識別する新しいルールを作成できます。 ケースのタイトルを使用して、識別および検索を容易にします。 非常に単純ですが、この例では最適化ルールで何が達成できるかを示しています。
ルールはアプリケーション データのチェックです。 ルールの評価条件が満たされた場合、プロセスを最適化したり、データを改善する案件が作成されます。 営業案件を対象にすることができ、必要に応じてアクションの影響を測定することができます。
最適化アドバイザーの新しいルールを作成するために、SelfHealingRule 抽象クラスを拡張する新しいクラスの追加、IDiagnosticsRule インターフェイスの実装、および DiagnosticRule 属性によって修飾がされます。 クラスは DiagnosticsRuleSubscription 属性で修飾されるメソッドも必要です。 慣例として、これは opportunityTitle メソッドで実行されます。これについては後で説明します。 この新しいクラスは SelfHealingRules に依存関係を持つカスタム モデルに追加することができます。 実装されている RFQTitleSelfHealingRule と呼ばれるルールを以下の例に示します。
[DiagnosticsRule]
public final class RFQTitleSelfHealingRule extends SelfHealingRule implements IDiagnosticsRule
{
…
}
SelfHealingRule 抽象クラスは、派生クラスで実装される必要がある抽象メソッドを持っています。 コアは評価方法です。ルールによって識別される案件の一覧を返します。 営業案件は法人ごと、またはシステム全体に適用できます。
protected List evaluate()
{
List results = new List(Types::Record);
DataArea dataArea;
while select id from dataArea
where !dataArea.isVirtual
{
changecompany(dataArea.id)
{
container result = this.findRFQCasesWithEmptyTitle();
if (conLen(result) > 0)
{
SelfHealingOpportunity opportunity = this.getOpportunityForCompany(dataArea.Id);
opportunity.EvaluationState = SelfHealingEvaluationState::Evaluated;
opportunity.Data = result;
opportunity.OpportunityDate = DateTimeUtil::utcNow();
results.addEnd(opportunity);
}
}
}
return results;
}
上記のメソッドは会社にループ、および findRFQCasesWithEmptyTitle メソッドで空のタイトルの RFQ ケースを選択します。 このようなケースが 1 つでも見つかった場合、getOpportunityForCompany メソッドで会社固有の営業案件が作成されます。 SelfHealingOpportunity テーブルの データ フィールドはタイプ コンテナーです。そのため、このルールに固有のロジックに適切なデータを含めることができます。 現在のタイムスタンプを持つ OpportunityDate 設定は営業案件の最新の評価の時間を登録します。
営業案件は会社間でも可能です。 この場合、会社にループすることは必要ではなく、営業案件は getOpportunityAcrossCompanies メソッドで作成される必要があります。
次のコードは findRFQCasesWithEmptyTitle メソッドを示しており、空のタイトルがある RFQ ケースの ID を返します。
private container findRFQCasesWithEmptyTitle()
{
container result;
PurchRFQCaseTable rfqCase;
while select RFQCaseId from rfqCase
where rfqCase.Name == ''
{
result += rfqCase.RFQCaseId;
}
return result;
}
実装される必要のあるさらに 2 つのメソッドは、opportunityTitle および opportunityDetails です。 前者は営業案件の簡単なタイトルを返し、後者は営業案件の詳細な説明を返します。これはデータを含めることもできます。
opportunityTitle によって返されるタイトルは、Optimization advisor ワークスペースの Optimization opportunity 列の下に表示されます。 作業ウィンドウのヘッダーとして、営業案件についての詳細情報が表示されます。 慣例として、DiagnosticRuleSubscription 属性でこのメソッドは修飾されます。このメソッドは次の引数を使用します。
診断エリア – DiagnosticArea::SCM のような、ルールが属するアプリケーションのどの領域かを説明する DiagnosticArea タイプの列挙型。
ルール名 – ルール名の文字列。 これは、診断検証ルール フォーム (DiagnosticsValidationRuleMaintain) 内の ルール名 コラムの下に表示されます。
実行頻度 – DiagnosticRunFrequency::Daily のような、どのくらいの頻度でルールが実行されるかを説明する DiagnosticRunFrequency タイプの列挙型。
ルールの説明 – ルールの詳細な説明の文字列。 これは、診断検証ルール フォーム (DiagnosticsValidationRuleMaintain) 内の ルールの説明 コラムの下に表示されます。
メモ
DiagnosticRuleSubscription 属性はルールが機能するために必要です。 通常、opportunityTitle で使用されますが、クラスの任意のメソッドで修飾できます。
実装例を次に示します。 未加工の文字列は単純化のために使用されていますが、正しい実装にはラベルが必要です。
[DiagnosticsRuleSubscription(DiagnosticsArea::SCM,
'Assign titles to Request for Quotation cases',
DiagnosticsRunFrequency::Daily,
'This rule detects Requests for Quotation with empty titles.')]
public str opportunityTitle()
{
return 'Assign titles to Request for Quotation cases';
}
opportunityDetails によって返された説明が作業ウィンドウに表示され、営業案件に関する詳細を示します。 これは SelfHealingOpportunity 引数を取ります。これは営業案件についての詳細を提供するために使用される データ フィールドです。 例では、メソッドは空のタイトルを持つ RFQ ケースの ID を返します。
public str opportunityDetails(SelfHealingOpportunity _opportunity)
{
str details = '';
container opportunityData = _opportunity.Data;
int affectedRFQCasesCount = conLen(opportunityData);
if (affectedRFQCasesCount != 0)
{
details = 'The following Request for Quotation cases have an empty title:\n';
for (int i = 1; i <= affectedRFQCasesCount ; i++)
{
PurchRFQCaseId rfqCaseId = conPeek(opportunityData, i);
details += rfqCaseId + '\n';
}
}
return details;
}
実装する残りの 2 つの抽象メソッドは provideHealingAction および securityMenuItem です。
provideHealingAction は修復アクションを指定すると true を返します。それ以外の場合は false を返します。 true が返された場合、performAction メソッドを実装する必要があるか、またはエラーがスローされます。 performAction メソッドは SelfHealingOpportunity 引数を取ります。この引数では、データをアクションに使用できます。 例では、手動で修正するために、アクションが PurchRFQCaseTableListPage を開きます。
public boolean providesHealingAction()
{
return true;
}
protected void performAction(SelfHealingOpportunity _opportunity)
{
new MenuFunction(menuItemDisplayStr(PurchRFQCaseTableListPage), MenuItemType::Display).run();
}
ルールの詳細によっては、営業案件データを使用して自動アクションを行うことが可能な場合もあります。 この例では、システムが RFQ ケースのタイトルを自動的に生成します。
securityMenuItem は、アクション メニュー項目にアクセスできるユーザーのみがルールを表示できるように、アクション メニュー項目の名前を返します。 セキュリティは、特定のルールや営業案件に許可されたユーザーのみがアクセスできることを求める場合があります。 この例では、PurchRFQCaseTitleAction へのアクセス権を持つユーザーのみが営業案件を見ることができます。 このアクション メニュー項目は、この例で作成され、PurchRFQCaseTableMaintain セキュリティ権限のエントリ ポイントとして追加されたことに注目してください。
メモ
メニュー項目は、セキュリティが正常に機能するためのアクション メニュー項目である必要があります。 メニュー項目の表示 などのその他のメニュー項目タイプは、正しく動作しません。
public MenuName securityMenuItem()
{
return menuItemActionStr(PurchRFQCaseTitleAction);
}
ルールがコンパイルされたら、次のジョブを実行してユーザー インターフェイス (UI) に表示させます。
class ScanNewRulesJob
{
public static void main(Args _args)
{
SysExtensionCache::clearAllScopes();
var controller = new DiagnosticsRuleController();
controller.runOperation();
}
}
ルールは 診断検証ルール フォームで表示され、システム管理>定期処理のタスク>診断検証ルールの管理 からも使用できます。 それを評価するために、システム管理>定期処理のタスク>診断検証ルールのスケジュール に移動し、毎日 のようなルールの頻度を選択します。 OK をクリックします。 システム管理>最適化アドバイザー に移動し、営業案件を表示します。
次の例は、すべての必要なメソッドと属性を含むルールのスケルトンを持つコード スニペットです。 これにより、新しいルールの作成を開始することができます。 この例で使用されているラベルとアクション メニュー項目は、デモ目的でのみ使用されます。
[DiagnosticsRuleAttribute]
public final class SkeletonSelfHealingRule extends SelfHealingRule implements IDiagnosticsRule
{
[DiagnosticsRuleSubscription(DiagnosticsArea::SCM,
"@SkeletonRuleLabels:SkeletonRuleTitle", // Label with the title of the rule
DiagnosticsRunFrequency::Monthly,
"@SkeletonRuleLabels:SkeletonRuleDescription")] // Label with a description of the rule
public str opportunityTitle()
{
// Return a label with the title of the opportunity
return "@SkeletonRuleLabels:SkeletonOpportunityTitle";
}
public str opportunityDetails(SelfHealingOpportunity _opportunity)
{
str details = "";
// Use _opportunity.data to provide details on the opportunity
return details;
}
protected List evaluate()
{
List results = new List(Types::Record);
// Write here the core logic of the rule
// When creating an opportunity, use:
// * this.getOpportunityForCompany() for company specific opportunities
// * this.getOpportunityAcrossCompanies() for cross-company opportunities
return results;
}
public boolean providesHealingAction()
{
return true;
}
protected void performAction(SelfHealingOpportunity _opportunity)
{
// Place here the code that performs the healing action
// To open a form, use the following:
// new MenuFunction(menuItemDisplayStr(SkeletonRuleDisplayMenuItem), MenuItemType::Display).run();
}
public MenuName securityMenuItem()
{
return menuItemActionStr(SkeletonRuleActionMenuItem);
}
}
詳細については、Dynamics 365 Finance の最適化アドバイザー という短い YouTube ビデオを確認する