最適化アドバイザーのルールを作成する
この記事では、最適化アドバイザーのための新しいルールを作成する方法について説明します。 例えば、見積依頼 (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 th atは、ルールが属するアプリケーションの特定の領域 (diagnosticArea::SCMなど) を表します。
ルール名 : ルール名の文字列です。 これは、診断検証ルール フォーム (DiagnosticsValidationRuleMaintain) 内の ルール名 コラムの下に表示されます。
実行頻度 : 列挙型 タイプ DiagnosticRunFrequency that)は、ルールを実行する頻度を示します ( DiagnosticRunFrequency::Daily)。
ルールの : ルールの詳細な説明を含む文字列。 これは、診断検証ルール フォーム (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 です。
provideAction 変更アクションが指定されている場合は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 ビデオを確認する