Note
コミュニティの関心グループが Yammer から Microsoft Viva Engage に移行されました。 Viva Engage コミュニティに参加し、最新のディスカッションに参加するには、「 Finance and Operations Viva Engage Community へのアクセスを要求する 」フォームに入力し、参加するコミュニティを選択します。
この記事では、X++ で倉庫モバイル プロセスを拡張する開発者のプロセス ガイド フレームワークに関する情報について説明します。 倉庫のモバイル プロセスは、プロセスが小さな手順に分割されるため、拡張可能です。 各ステップのビジネス ロジックとユーザー インターフェイスの構築は、個々のクラスに抽出され、拡張性が可能になります。
既存のデザインの概要
倉庫モバイル実行フローは、1 つのカスタム サービス エンドポイントを通じて公開されます。 要求は、モバイル アプリに表示されるユーザー インターフェイスのメタデータと、ユーザーが入力した値を含む XML 文字列の形式でモバイル アプリから到着します。
要求を受信したら、最初に XML を逆シリアル化します。
WHSMobileAppServiceXMLTranslator クラスは、コントロール情報とセッション情報の両方を保持するコンテナーに XML を変換します。
次に、コンテナー内の情報を使用して、ユーザーが作業している、または開始しようとしているウェアハウス プロセスを決定します。 このプロセスは、 WHSWorkExecuteMode 列挙体によって表されます。 この情報に基づいて、 WHSWorkExecuteDisplay の派生クラスがインスタンス化されます。
displayform() メソッドが呼び出され、次のアクションが実行されます。
- ユーザーからのデータを処理します (
WHSRFControlDataクラスに委任されますが、一部のプロセスでは、processControl()メソッドをオーバーライドして特定のロジックを実装します)。 - ビジネス ロジックを実行します。
- ステップが増加します。
- 新しいユーザー インターフェイスを表すコンテナーをビルドします (通常は
build…()メソッド内)。
その後、コンテナーがトランスレーターに返され、XML がシリアル化され、モバイル デバイスへの応答として返されます。
次の順序図では、実行フローの概要を示します。 この図は、より概略的な概要であり、実際のコードの 1 対 1 の表現ではありません。
再設計の理由
この設計は、モバイル フローで使用されるプロセスを構築するためのシンプルなフレームワークを提供します。 ただし、 displayform() メソッドは複数の責任を負います。 これらの責任を他のメソッドやクラスに委任しますが、具体的なクラスの責任がなければ、この委任はクラス間で一貫性がありません。 サポートされるシナリオの数が有機的に増えるにつれて、これらのクラスの一部が複雑になります。 さらに、これらのクラス/メソッドの一部はオーバーライドされ、複数のモードで再利用されます。 その結果、サイクロマティック複雑度の高い長いメソッドが得られます。 これらの方法では、過去にメンテナンスの問題が発生しました。 これらのメソッドのバグを修正すると、リスクが高く、回帰が発生しやすくなります。 たとえば、processWorkLine() クラスのWhsWorkExecuteDisplay メソッドは、複数のプロセス (基本的には、作業実行が実行される任意の場所) から参照されます。
これらのメソッドを拡張可能にするには、 displayForm メソッドをより小さなメソッドに分割し、拡張ポイントを導入できます。 ただし、シナリオ マトリックスのため、拡張機能を記述し、逆光を検証することはパートナーにとって困難です。 それだけでなく、前述の構造化された責任配分がないため、コードは時間の経過とともに予測不可能な方法で成長し続け、品質拡張の構築に課題を生み出します。
その結果、再設計は持続可能な選択肢であり、独立した責任を持つ明確に定義されたクラスを持つことが目標です。 クラスの職責、変更する理由、拡張する理由は 1 つにする必要があります。
設計の概要
再設計されたフレームワークでは、実行フローを適切に定義された役割を持つ個々のコンポーネントに分割し、各コンポーネントに明確に定義された拡張ポイントを含めるという 2 つの主要な原則を使用します。
新しいフレームワークの名前は ProcessGuide です。 これらのクラスの目的は、リッチ クライアントとは対照的に、ビジネス プロセスをユーザーに案内することです。これは、ユーザーがデータを操作する方法やタスクを実行する順序に柔軟性を持つフォーム ベースのエクスペリエンスです。
Note
注目すべき詳細の 1 つは、 WHS プレフィックスの意図的な省略です。 モバイル プロセスは最初に倉庫に導入されましたが、現在はさまざまな生産および在庫管理プロセスをサポートしています。 その結果、倉庫の参照はフレームワークの名前から除外されました。
コンポーネントを識別するには、運用開始プロセス (WhsWorkExecuteDisplayProdStart クラス) を参照してください。 プロセスの概要を次に示します。
制御フローを見ると、次のコンポーネントが必要です。
- ビジネス プロセス全体を管理するコントローラー。
- プロセスでステップの実行を担当するステップ。
- ステップ内のデータを処理するためのデータ プロセッサ。
- ステップのユーザー インターフェイスの作成を担当するページ ビルダー。
- ステップの移行を担当するナビゲーション エージェント。
- 業務プロセスの実行を担当するクラス。
プロセス フロー図で、手順 1 で開始し、前の手順のデータの処理を開始した後、UI の構築で終了した場合、データは次の手順で引き続き処理されます。 この方法では、連続するステップ間の緊密な結合が導入されます。 その結果、新しい高レベルの概略図は以下のようになります。
再設計されたプロセスの主要なコンポーネントは次のとおりです。
-
ProcessGuideController- このクラスは、ビジネス プロセスの全体的な実行を調整します。 ステップをインスタンス化するファクトリと、後でプロセスの実行を構成するナビゲーション エージェント、およびプロセスをキャンセルまたは終了するためのクリーンアップ ロジックを定義します。 -
ProcessGuideStep- このクラスは、ビジネス プロセスの 1 つのステップを表します。 これには、ページ ビルダー、アクション、およびデータ プロセッサをインスタンス化するファクトリの定義が含まれています。 それは、それらを正しい順序で呼び出す役割を担っています。 -
ProcessGuideNavigationAgent- このクラスは、手順間のナビゲーションを担当します。 ステップが完了すると、ナビゲーション エージェントは次のステップを定義し、前の手順で次のステップと通信するために必要なパラメーターを渡します。 -
ProcessGuidePageBuilder- このクラスは、ユーザー インターフェイスのインスタンス化を担当します。 -
ProcessGuideAction- このクラスは、ユーザーにボタンとして表示されるアクションを表します。 -
ProcessGuideDataProcessor- このクラスは、ユーザーがフィールドに入力したデータを処理します。
実行フロー
実行フローの開始点は変更されないままです。 そのため、要求は引き続き同じエンドポイントに到着し、その後、コンテナーに XML が逆シリアル化されます。 このコンテナーは、 getNextFormState()に渡されます。
注目すべき次の 3 つの重要なクラスがあります。
-
ProcessGuideSessionState– セッション状態情報 (モード、パス、コントローラー、実行中のステップなど) が含まれます。 -
ProcessGuidePage– これには、ユーザー インターフェイス メタデータの厳密に型指定された表現が含まれます。 -
ProcessGuideRequest– これは、上記の 2 つをメンバーとして含み、モバイル デバイスから受信した要求の厳密に型指定された表現です。
これらのクラスは、コンテナー情報を使用して作成されます (状態とユーザー入力管理データの両方)。 これにより、値にアクセスして操作するためのタイプ セーフな方法が提供されます。 プロセス中のコンテナーの繰り返しアクセスと比較して、これは、信頼性とパフォーマンスの両方に関して利点を生み出します。
セッション状態情報は、適切な ProcessGuideController クラスをインスタンス化するために使用されます。 インスタンス化されると、createResponse() クラスのProcessGuideController メソッドが呼び出されます。 このメソッドはプロセス ガイド ロジックのエントリ ポイントであり、実行後に応答が返されます ( ProcessGuideResponse クラスで表されます)。 応答は、その後コンテナーに変換されて、レガシ トピックに戻された後、XML にシリアル化され、応答がモバイル デバイスに戻されます。
次に、コントローラーは実行する次の手順を見つける必要があります。 これが新しいプロセスの開始である場合、コントローラーはプロセスの最初のステップを取得するために initialStep() を呼び出します。 その後、ProcessGuideStep内のexecute()メソッドを呼び出します。 このメソッドは、 ProcessGuidePageBuilder クラスをインスタンス化し、 buildPage()を呼び出します。 ProcessGuidePage オブジェクトが返されます。これは、ユーザーに表示されるユーザー インターフェイスの仮想表現です。 その後、ステップによって結果がコントローラーに送り返され、現在のセッション状態が保存され、結果が getNextFormState() クラスの形式でProcessGuideResponseに返されます。 その後、応答はコンテナーに変換され、後で XML にシリアル化され、応答がモバイル デバイスに返されます。
次のシーケンス図では、この制御フローについて説明します。 これは最も一般的な制御フローであり、設計を説明するために簡略化されています。
ユーザーがボタンを選択してモバイル デバイスでアクションを実行する (または値をスキャンすると、通常は既定のアクションがトリガーされます) 場合、要求は同じルートを介して createResponse() クラスの ProcessGuideController メソッドに到着します。 ただし、このとき、コントローラーはセッション状態情報から、ユーザーがいるステップを知ります。 したがって、適切な ProcessGuideStep クラスをインスタンス化し、execute メソッドを呼び出します。
ProcessGuideStepは、ユーザーによって呼び出されたアクション名を読み取り、適切なProcessGuideAction クラスをインスタンス化し、execute()を呼び出します。
ProcessGuideAction クラスは特定のアクションの実行を担当しますが、2 つの注目すべき例外があります。
1 つ目は、 ProcessGuideOKAction クラスです。 このアクションは、ユーザーがプロセスを確認して前に動かすことを求めていることを意味します。 これに従って、このメソッドは実際には ProcessGuideStep クラスへのコールバックを実行します。つまり、ステップはprocessData()でProcessGuideDataProcessorを呼び出します。 これは、ユーザーが入力したデータを処理し、ステップの状態を更新し、結果をコントローラーに返します。 プロセッサの結果によっては、ステップは適切なユーザー インターフェイスを構築するためのページ ビルダーを起動するか、ステップのステータスを完了に設定します。 これは、次のシーケンス図の上半分に反映されます。
もう 1 つの例外は、 ProcessGuideCancelResetProcessAction クラスと ProcessGuideCancelExitProcessAction クラスに実装されているキャンセル アクションです。 これらのアクションは、処理をキャンセルする意図を表し、プロセスの開始またはプロセスの終了を完全に戻します。
OK アクションと同様に、これらのアクションはステップへのコールバックも実行します。これにより、意図がProcessGuideControllerに通知されます。 その後、コントローラーは状態変数の必要なクリーンアップを実行し、コントロールをプロセスにおける最初のステップに移動するか、プロセスを完全に終了します。
ステップが完了した後、ステップの状態が 完了に設定されている場合、コントローラーは ProcessGuideNavigationAgentをインスタンス化し、次のステップの名前を返します。 その後、コントローラーはこのステップをインスタンス化し、 execute() メソッドを呼び出します。サイクルは続行されます。 通常は、新しいステップによって対応する ProcessGuidePageBuilder が呼び出され、ユーザーに次に表示する画面のユーザーインターフェイスが構築され、その後それが返送されます。 このフローは、次のシーケンス図の下半分に示されています。
ProcessGuide フレームワークを使用した新しいプロセスの構築
制御フローを説明する最善の方法は、アプリケーションに存在している例を使用することです (生産開始プロセス)。
生産開始プロセスの概要
まず、プロセス フローを理解しましょう。 最初の手順で、ユーザーは製造オーダー ID の入力を求められます。
製造オーダー ID をユーザーが入力すると、注文番号が検証されます。 実行される検証の一部は、注文がユーザーがサインインしたのと同じ倉庫にあるかどうか、および注文の状態に基づいています。 検証に失敗すると、ユーザーにエラー メッセージが表示されます。 検証が成功すると、ユーザーには製造オーダーと品目の詳細が表示されます。
ユーザーはキャンセルしてプロセスの開始に戻るか、[ OK] を 選択して確認できます。 後者の場合、製造オーダーが 開始 状態に設定され、対応する仕訳帳が転記され、コントロールが最初のステップに戻り、 作業完了 メッセージがユーザーに表示されます。
コントローラーの作成
ビジネス プロセスを構築する最初の手順は、コントローラーの既定の動作を実装する ProcessGuideController 抽象クラスから拡張して、コントローラー クラスを作成することです。 新しいクラス名はProdProcessGuideProductionStartControllerされ、WHSWorkExecuteModeのStartProdOrder値で修飾されます。
SysExtension クラスで既に使用されているのと同じWHSWorkExecuteDisplay ベースのインスタンス化がここで使用されます。これにより、ユーザーがこのモードのメニュー項目を実行するときにコントローラーをインスタンス化するのに役立ちます。
[WHSWorkExecuteMode(WHSWorkExecuteMode::StartProdOrder)]
public class ProdProcessGuideProductionStartController extends ProcessGuideController
Note
クラスの名前付けパターンは \<FunctionalArea\>ProcessGuide\<Businessprocessname\>Controller。 これは、コントローラー クラスと他のクラスに拡張するために使用されるパターンです
最初のステップの作成
次に、ProdProcessGuidePromptProductionIdStepを拡張する ProcessGuideStep クラスを作成して、最初の手順を定義します。
ステップ ファクトリによってクラスがインスタンス化されます。
ProcessGuideController基本クラスはファクトリを呼び出します。 ファクトリの既定の実装は、名前に基づいてステップをインスタンス化します。 コントローラーの最初の手順として ProdProcessGuidePromptProductionIdStep をインスタンス化するには、次の 2 つのタスクを実行します。
ProdProcessGuidePromptProductionIdStep属性を使用して、ProcessGuideStepNameクラスを装飾します。[ProcessGuideStepName(classStr(ProdProcessGuidePromptProductionIdStep))] public class ProdProcessGuidePromptProductionIdStep extends ProcessGuideStepコントローラー クラスで、ステップ名を返
initialStepName()抽象メソッドを実装します。protected final ProcessGuideStepName initialStepName() { return classStr(ProdProcessGuidePromptProductionIdStep); }
Note
ProcessGuideStepName属性の値は、前のコードに示すように、クラス名と完全に一致する必要はありません。 ただし、この属性を実装すると、クラスを使用する際の相互参照に関する統一性と型安全性が可能になります。 この名前付け規則を使用します。
ステップの ProcessGuideStepName ベースのインスタンス化は、 ProcessGuideStepDefaultFactory クラスに実装されます。 まれに、ステップをインスタンス化するための別の戦略が必要な場合は、次のタスクを実行します。
-
ProcessGuidStepAbstractFactoryから継承する新しいファクトリ クラスを作成します。 - 必要に応じて、ファクトリに必要なパラメーターを含む
ProcessGuideIStepCreationParametersインターフェイスを実装する新しいパラメーター クラスを作成します。 - コントローラー クラスで、
stepFactory()メソッドとstepCreationParameters()メソッドをオーバーライドして、上記のファクトリとパラメーターを返します。
次に、 ProdProcessGuidePromptProductionIdStep クラスの機能を実装します。 ユーザー インターフェイスを構築し、ユーザーが入力したデータを処理し、ステップが完了したタイミングを決定するためのロジックを実装します。
最初のステップのユーザー インターフェイスの構築
ProcessGuidePageBuilder抽象クラスから継承するクラスを作成して、ユーザー インターフェイスを構築します。 この手順では、クラスに何を行うかを表す名前 ( ProdProcessGuidePromptProductionIdPageBuilder) を指定します。
クラスのインスタンス化メカニズムは、コントローラーからステップをインスタンス化する方法と似ています。
ProdProcessGuidePromptProductionIdPageBuilder属性を使用して、ProcessGuidePageBuilderNameクラスを装飾します。[ProcessGuidePageBuilderName(classStr(ProdProcessGuidePromptProductionIdPageBuilder))] public class ProdProcessGuidePromptProductionIdPageBuilder extends ProcessGuidePageBuilderProdProcessGuidePromptProductionIdStepクラスで、この名前を返pageBuilderName()抽象メソッドを実装します。protected final ProcessGuidePageBuilderName pageBuilderName() { return classStr(ProdProcessGuidePromptProductionIdPageBuilder); }
Tip
ステップ ファクトリと同様に、ページ ビルダー ファクトリ用に実装された抽象ファクトリ パターンもあります。 ですから、まれに、異なる戦略でページ ビルダーのインスタンス化が必要になることがありますが、その場合は次のようにすることができます。
-
ProcessGuidePageBuilderAbstractFactoryから継承する新しいファクトリ クラスを作成します。 - 必要に応じて、ファクトリに必要なパラメーターを含む
ProcessGuideIPageBuilderCreationParametersインターフェイスを実装する新しいパラメーター クラスを作成します。 - ステップ クラスで、
pageBuilderFactory()メソッドとpageBuilderCreationParameters()メソッドをオーバーライドしてファクトリとパラメーターを返します。
ユーザー インターフェイスを実装するには、1 つのテキスト ボックスに製造オーダー ID を入力するページと、[ OK] ボタンと [キャンセル ] ボタンが必要です。 キャンセル ボタンは、プロセスを終了する必要があります。
この UI を実装するには、 ProdProcessGuidePromptProductionIdPageBuilder クラスの 2 つのメソッドをオーバーライドします。
テキスト ボックスを追加するには、
addDataControls()メソッドを使用します。protected final void addDataControls(ProcessGuidePage _page) { _page.addTextBox(ProcessGuideDataTypeNames::ProdId, "@SYS4398", extendedTypeNum(ProdId)); }addActionControls()メソッドを使用して、[OK] ボタンと [キャンセル] ボタンを追加します。protected final void addActionControls(ProcessGuidePage _page) { #ProcessGuideActionNames _page.addButton(step.createAction(#ActionOK), true); _page.addButton(step.createAction(#ActionCancelExitProcess)); }
この方法では、データ コントロールの後にボタンが追加されます。 ただし、複数のデータ コントロールとボタンを含む画面を作成する場合は、 addControls() メソッドをオーバーライドして柔軟性を高めることができます。
考慮すべきもう 1 つのシナリオは、ユーザーが間違った製造オーダー ID を入力したときなど、検証エラーが発生した場合にページを再構築する方法です。
ProcessGuidePageBuilder基本クラスは、ユーザー インターフェイスを再構築し、スキャンされた値をクリアし、エラー メッセージを含むエラー コントロールを追加する既定の動作を実装します。 これは使用する既定の動作であるため、エラーを処理するためのコードを追加する必要はありません。
Tip
エラー状況に対してカスタム UI 動作を実装する場合は、 rebuildFromRequestPage()、 isErrorState()、 reuseRequestPageOnError()の 1 つ以上のメソッドをオーバーライドできます。
最初の手順でユーザーが入力したデータの処理
データの処理は、 ProcessGuideDataProcessorDefault クラスで行われ、レガシ WhsRfControlData クラスが呼び出されます。 この既定の動作を変更する必要はなく、 WhsRfControlData には ProdId フィールドを検証するためのロジックが既に用意されているため、これを処理するためのロジックを記述する必要はありません。 検証ロジックに拡張機能が必要な場合は、 WhsControl ベースの拡張メカニズムの使用を検討してください。
最初の手順が完全であるかどうかを判断
検証が成功したら、ステップを完了としてマークします。 基底クラスはこのアクションを処理しますが、ステップの完了を決定する条件を実装する必要があります。 次のオーバーライドされたメソッドは、この条件を実装します。
protected final boolean isComplete()
{
WhsrfPassthrough pass = controller.parmSessionState().parmPass();
ProdId prodId = pass.lookup(ProcessGuideDataTypeNames::ProdId);
return (prodId != '');
}
注文の詳細を表示して確認する
プロセスの 2 番目の手順では、注文に関する詳細を含む画面がユーザーに表示されます。 ユーザーは、[ OK ] ボタンを選択して製造オーダーの開始を確認するか、[ キャンセル] を選択してプロセスの開始に戻ることができます。 この例では、ステップ ProdProcessGuideConfirmProductionOrderStep とページ ビルダー クラスに ProdProcessGuideConfirmProductionOrderPageBuilder名前を付けます。
ProdProcessGuideConfirmProductionOrderStep クラスは次のようになります。
[ProcessGuideStepName(classStr(ProdProcessGuideConfirmProductionOrderStep))]
public class ProdProcessGuideConfirmProductionOrderStep extends ProcessGuideStep
{
protected final ProcessGuidePageBuilderName pageBuilderName()
{
return classStr(ProdProcessGuideConfirmProductionOrderPageBuilder);
}
}
ユーザーはここに値を入力しないため、 isComplete() メソッドをオーバーライドする必要はありません。 ユーザーが [OK] を選択すると、手順が完了します。
ページ ビルダー クラスは、 addDataControls() メソッドをオーバーライドして 3 つのラベルを追加します。 最初のラベルには、製造オーダー ID が表示されます。 2 番目のラベルには、アイテム ID、ディメンション、説明などのアイテム情報が含まれています。 3 番目のラベルには、数量と数量単位が含まれています。
addActionControls() メソッドは、2 つのボタンを追加するためにオーバーライドされます。[OK] ボタンと、[キャンセル] ボタンをクリックしてプロセスをキャンセルし、プロセスの開始に戻ります。
/// <summary>
/// The <c>ProdProcessGuideConfirmProductionOrderPageBuilder</c> builds a page that allows the user to see details of a production order
/// and then confirm.
/// </summary>
[ProcessGuidePageBuilderName(classStr(ProdProcessGuideConfirmProductionOrderPageBuilder))]
public class ProdProcessGuideConfirmProductionOrderPageBuilder extends ProcessGuidePageBuilder
{
protected void addDataControls(ProcessGuidePage _page)
{
WhsrfPassthrough pass = controller.parmSessionState().parmPass();
ProdTable prodTable = ProdTable::find(pass.lookup(ProcessGuideDataTypeNames::ProdId));
UnitOfMeasureSymbol inventUOM = InventTableModule::find(prodTable.ItemId, ModuleInventPurchSales::Invent).UnitId;
_page.addLabel(ProcessGuideDataTypeNames::ProdIdLabelName, strFmt("@WAX1684", prodTable.ProdId), extendedTypeNum(ProdId));
_page.addLabel(ProcessGuideDataTypeNames::ItemInfo, this.generateItemInfoForProdId(pass.lookup(ProcessGuideDataTypeNames::ProdId)), extendedTypeNum(WHSRFUndefinedDataType));
_page.addLabel(ProcessGuideDataTypeNames::QtyLabelName, strFmt("@WAX1685", WHSWorkExecuteDisplay::num2StrDisplay(ProdUpdStartUp::proposalStartUpQty(prodTable.ProdId)), inventUOM), extendedTypeNum(WHSRFQuantityAndUOM));
if (PdsGlobal::pdsIsCWItem(prodTable.ItemId))
{
_page.addLabel(ProcessGuideDataTypeNames::InventQtyLabelName, strFmt("@WAX1685", WHSWorkExecuteDisplay::num2StrDisplay(ProdUpdStartUp::pdsCWProposalStartupQty(prodTable.ProdId)), PdsCatchWeightItem::pdsCWUnitId(prodTable.ItemId)), extendedTypeNum(WHSRFQuantityAndUOM));
}
}
protected void addActionControls(ProcessGuidePage _page)
{
#ProcessGuideActionNames
_page.addButton(step.createAction(#ActionOK), true);
_page.addButton(step.createAction(#ActionCancelResetProcess));
}
Note
この記事では、X++ メソッドに対して同じソースコードをアプリケーションエクスプローラーを使用して検索できます。 クラス名をフィルター処理し、クラス名を右クリックして コードの表示を選択します。
製造オーダーを開始する
3 番目の手順では、製造オーダーを開始するためのビジネス ロジックを実行します。 ユーザー インターフェイスがないため、この手順は前の手順とは異なります。 この手順は、ユーザーが前の手順で [OK] を 選択すると、自動的に実行されます。
ProcessGuideStepWithoutPrompt抽象クラスは、このような手順の既定の動作を実装します。 したがって、現在の手順では、 ProcessGuideStepWithoutPrompt クラスを拡張し、 doExecute() メソッドをオーバーライドする必要があります。
次のコード例は、クラスと doExecute() メソッドの実装を示しています。 このメソッドは、セッション状態から注文 ID とユーザー ID を取得し、メソッドを呼び出してこの製造オーダーを開始します。
/// <summary>
/// The <c>ProdProcessGuideStartProductionOrderStep</c> represents a step that starts a production order.
/// </summary>
[ProcessGuideStepName(classStr(ProdProcessGuideStartProductionOrderStep))]
public class ProdProcessGuideStartProductionOrderStep extends ProcessGuideStepWithoutPrompt
{
protected final void doExecute()
{
WhsrfPassthrough pass = controller.parmSessionState().parmPass();
WHSUserId userId = pass.lookup(ProcessGuideDataTypeNames::UserId);
ProdTable prodTable = ProdTable::find(pass.lookup(ProcessGuideDataTypeNames::ProdId));
WhsWorkExecute workExecute = WhsWorkExecute::construct();
workExecute.prodStartUp(prodTable.ProdId, ProdUpdStartUp::proposalStartUpQty(prodTable.ProdId), userId);
this.addProcessCompletionMessage();
super();
}
}
例外が発生した場合、フレームワーク例外処理ロジックは、プロセスを前の手順にロールバックします。
Note
addProcessCompletionMessage()の呼び出しにより、作業完了メッセージがナビゲーション パラメーターに追加されます。 次の手順 (ユーザー インターフェイスがある場合) は、このメッセージを表示します。 基本クラスは、このロジックを処理するため、この動作を実現するために特定のコードをプロセス クラスに追加する必要はありません。
ステップでのナビゲーションの構築
ProcessGuideController基底クラスは、定義済みのナビゲーション ルートに依存するProcessGuideNavigationAgentDefault クラスをインスタンス化します。 このルートは、ソースステップと宛先ステップの単純なマップです。 運用環境の開始シナリオでは、条件付き分岐がないため、この実装は機能します。 したがって、ナビゲーション ルートを定義するには、 initializeNavigationRoute() メソッドをオーバーライドする必要があります。
protected ProcessGuideNavigationRoute initializeNavigationRoute()
{
ProcessGuideNavigationRoute navigationRoute = new ProcessGuideNavigationRoute();
navigationRoute.addFollowingStep(classStr(ProdProcessGuidePromptProductionIdStep), classStr(ProdProcessGuideConfirmProductionOrderStep));
navigationRoute.addFollowingStep(classStr(ProdProcessGuideConfirmProductionOrderStep), classStr(ProdProcessGuideStartProductionOrderStep));
navigationRoute.addFollowingStep(classStr(ProdProcessGuideStartProductionOrderStep), classStr(ProdProcessGuidePromptProductionIdStep));
return navigationRoute;
}
一部のプロセスでは、(ユーザーアクションやその他の条件に基づいて) 条件付き分岐が必要です。 このようなプロセスでは、次のタスクを実行する必要があります。
-
ProcessGuideNavigationAgentクラスから継承された特定のナビゲーション エージェントを実装します。 - 現在のステップ、セッション状態、ユーザー アクション、またはその他のロジックに基づいて適切なナビゲーション エージェントをインスタンス化するロジックを含む、
ProcessGuideNavigationAgentAbstractFactoryクラスから継承された特定のナビゲーション エージェント ファクトリを実装します。 - 必要に応じて、コントローラー クラスの
navigationAgentCreationParameters()をオーバーライドして、適切なパラメーターを渡します。 - コントローラーの
navigationAgentFactory()をオーバーライドして、前に作成したナビゲーション エージェント ファクトリをインスタンス化します。
アクション クラス
アクション クラスはユーザーの操作を表すため、この例では、 OK アクションを使用して、アクションの作成方法を表示します。
[ProcessGuideActionName(#ActionOK)]
public class ProcessGuideOKAction extends ProcessGuideAction
{
public final str label()
{
return "@SYS5473";
}
protected final void doExecute()
{
step.executeOKAction();
}
}
このクラスは、次の 2 つの抽象メソッドを実装する必要があります。
-
label(): このアクションに関連付けられたボタン コントロールに表示されるラベルを返します。 -
doExecute():アクションを実行します。 既に述べたように、OK ボタンはステップでコールバックを実行するだけです。 ただし、他のアクションには、より複雑なロジックが含まれます。
アクションは、SysExtension属性に基づいてProcessGuideActionNameフレームワークを使用してインスタンス化されます。 ページ ビルダーのインスタンス化と同様に、ステップ クラスは既定のアクション ファクトリを実装し、それをオーバーライドすることができます。 ページ ビルダーは、次のようにボタン コントロールを追加します。
_page.addButton(step.createAction(#ActionOK), true);
ボタンを追加すると、渡された名前のアクション クラスを作成し、そのアクションをボタンに結び付けるステップが求められます。
まとめ
この記事で説明されているすべてを要約するために、プロセスに必要なコードの包括的な概要を次に示します。
ProdProcessGuideProductionStartControllerinitialStepName()をオーバーライドして、最初の手順の名前を指定します。initializeNavigationRoute()をオーバーライドしてナビゲーション マップを構築します。/// <summary> /// The <c>ProdProcessGuideProductionStartController</c> class is the controller class for the production order start process guide. /// </summary> [WHSWorkExecuteMode(WHSWorkExecuteMode::StartProdOrder)] public class ProdProcessGuideProductionStartController extends ProcessGuideController { protected ProcessGuideStepName initialStepName() { return classStr(ProdProcessGuidePromptProductionIdStep); } protected ProcessGuideNavigationRoute initializeNavigationRoute() { ProcessGuideNavigationRoute navigationRoute = new ProcessGuideNavigationRoute(); navigationRoute.addFollowingStep(classStr(ProdProcessGuidePromptProductionIdStep), classStr(ProdProcessGuideConfirmProductionOrderStep)); navigationRoute.addFollowingStep(classStr(ProdProcessGuideConfirmProductionOrderStep), classStr(ProdProcessGuideStartProductionOrderStep)); navigationRoute.addFollowingStep(classStr(ProdProcessGuideStartProductionOrderStep), classStr(ProdProcessGuidePromptProductionIdStep)); return navigationRoute; } }
ProdProcessGuidePromptProductionIdStepisComplete()をオーバーライドして、ステップが完了したと見なされるタイミングを指定します。pageBuilderName()をオーバーライドして、使用するページ ビルダーを指定します。/// <summary> /// The <c>ProdProcessGuidePromptProductionIdStep</c> represents a step that /// that prompts the user for a production order id. /// </summary> [ProcessGuideStepName(classStr(ProdProcessGuidePromptProductionIdStep))] public class ProdProcessGuidePromptProductionIdStep extends ProcessGuideStep { protected boolean isComplete() { WhsrfPassthrough pass = controller.parmSessionState().parmPass(); ProdId prodId = pass.lookup(ProcessGuideDataTypeNames::ProdId); return (prodId != ''); } protected ProcessGuidePageBuilderName pageBuilderName() { return classStr(ProdProcessGuidePromptProductionIdPageBuilder); } }
ProdProcessGuidePromptProductionIdPageBuilderaddDataControls()をオーバーライドして、Prod IDテキストボックスを追加します。addActionControls()をオーバーライドして、[OK] ボタンと [キャンセル] ボタンを追加します。/// <summary> /// The <c>ProdProcessGuidePromptProductionIdPageBuilder</c> class builds a page /// that prompts the user for a production order id. /// </summary> [ProcessGuidePageBuilderName(classStr(ProdProcessGuidePromptProductionIdPageBuilder))] public class ProdProcessGuidePromptProductionIdPageBuilder extends ProcessGuidePageBuilder { protected void addDataControls(ProcessGuidePage _page) { _page.addTextBox(ProcessGuideDataTypeNames::ProdId, "@SYS4398", extendedTypeNum(ProdId)); } protected void addActionControls(ProcessGuidePage _page) { #ProcessGuideActionNames _page.addButton(step.createAction(#ActionOK), true); _page.addButton(step.createAction(#ActionCancelExitProcess)); } }
ProdProcessGuideConfirmProductionOrderSteppageBuilderName()をオーバーライドして、使用するページ ビルダーを指定します。/// <summary> /// The <c>ProdProcessGuideConfirmProductionOrderStep</c> class represents the step for viewing production order /// details and confirming the same. /// </summary> [ProcessGuideStepName(classStr(ProdProcessGuideConfirmProductionOrderStep))] public class ProdProcessGuideConfirmProductionOrderStep extends ProcessGuideStep { protected ProcessGuidePageBuilderName pageBuilderName() { return classStr(ProdProcessGuideConfirmProductionOrderPageBuilder); } }
ProdProcessGuideConfirmProductionOrderPageBuilderaddDataControls()をオーバーライドして、注文、品目、数量の情報ラベルを追加します。addActionControls()をオーバーライドして、[OK] ボタンと [キャンセル] ボタンを追加します。/// <summary> /// The <c>ProdProcessGuideConfirmProductionOrderPageBuilder</c> builds a page that allows the user to see details of a production order /// and then confirm. /// </summary> [ProcessGuidePageBuilderName(classStr(ProdProcessGuideConfirmProductionOrderPageBuilder))] public class ProdProcessGuideConfirmProductionOrderPageBuilder extends ProcessGuidePageBuilder { protected void addDataControls(ProcessGuidePage _page) { WhsrfPassthrough pass = controller.parmSessionState().parmPass(); ProdTable prodTable = ProdTable::find(pass.lookup(ProcessGuideDataTypeNames::ProdId)); UnitOfMeasureSymbol inventUOM = InventTableModule::find(prodTable.ItemId, ModuleInventPurchSales::Invent).UnitId; _page.addLabel(ProcessGuideDataTypeNames::ProdIdLabelName, strFmt("@WAX1684", prodTable.ProdId), extendedTypeNum(ProdId)); _page.addLabel(ProcessGuideDataTypeNames::ItemInfo, this.generateItemInfoForProdId(pass.lookup(ProcessGuideDataTypeNames::ProdId)), extendedTypeNum(WHSRFUndefinedDataType)); _page.addLabel(ProcessGuideDataTypeNames::QtyLabelName, strFmt("@WAX1685", WHSWorkExecuteDisplay::num2StrDisplay(ProdUpdStartUp::proposalStartUpQty(prodTable.ProdId)), inventUOM), extendedTypeNum(WHSRFQuantityAndUOM)); if (PdsGlobal::pdsIsCWItem(prodTable.ItemId)) { _page.addLabel(ProcessGuideDataTypeNames::InventQtyLabelName, strFmt("@WAX1685", WHSWorkExecuteDisplay::num2StrDisplay(ProdUpdStartUp::pdsCWProposalStartupQty(prodTable.ProdId)), PdsCatchWeightItem::pdsCWUnitId(prodTable.ItemId)), extendedTypeNum(WHSRFQuantityAndUOM)); } } protected void addActionControls(ProcessGuidePage _page) { #ProcessGuideActionNames _page.addButton(step.createAction(#ActionOK), true); _page.addButton(step.createAction(#ActionCancelResetProcess)); }Note
アイテム情報ラベルの生成に使用される
generateItemInfoForProdId()メソッドは、この記事から除外されています。 このメソッドは、品目 ID、説明、および分析コードを取得するいくつかのテーブルを照会します。generateItemInfoForProdId()について理解を深めたい場合は、ソース コードを参照してください。
ProdProcessGuideStartProductionOrderStepdoExecute()をオーバーライドして運用開始プロセスを実行し、プロセス完了メッセージを追加します。/// <summary> /// The <c>ProdProcessGuideStartProductionOrderStep</c> represents a step that starts a production order. /// </summary> [ProcessGuideStepName(classStr(ProdProcessGuideStartProductionOrderStep))] public class ProdProcessGuideStartProductionOrderStep extends ProcessGuideStepWithoutPrompt { protected final void doExecute() { WhsrfPassthrough pass = controller.parmSessionState().parmPass(); WHSUserId userId = pass.lookup(ProcessGuideDataTypeNames::UserId); ProdTable prodTable = ProdTable::find(pass.lookup(ProcessGuideDataTypeNames::ProdId)); WhsWorkExecute workExecute = WhsWorkExecute::construct(); workExecute.prodStartUp(prodTable.ProdId, ProdUpdStartUp::proposalStartUpQty(prodTable.ProdId), userId); this.addProcessCompletionMessage(); super(); } }
Note
一般的なパターンの多く (エラー時の UI の再生成、プロセス完了メッセージの設定、 OK と キャンセル の動作) がフレームワークの一部になりました。 この変更により、アプリケーション開発者は、エラーが発生しやすく、プロセス間で一貫性のない動作のリスクがある定型コードを記述できなくなります。 シナリオが共通パスから逸脱する必要がある場合、アプリケーション開発者は適切なメソッドをオーバーライドできます。 この偏差は意図的、明示的、追跡可能です。
業務プロセスの拡張
ここまで、この記事では、 ProcessGuide フレームワークを使用して新しいプロセスを構築する方法について説明します。 この最後のセクションでは、このビジネス プロセスを拡張する方法の例をいくつか示します。
フローにおけるステップの追加 (ProcessGuideNavigationAgentDefault を使用)
拡張場所:
- プロセスの
ProcessGuideControllerクラスの子。
拡張方法:
- コントローラー クラスで
initializeNavigationRoute()メソッドを拡張し、addFollowingStep()クラスでProcessGuideNavigationRouteを呼び出します。
フローにおけるステップの追加 (カスタム ナビゲーション エージェントを使用)
拡張場所:
-
ProdProcessGuideNavigationAgentFactory/ProdProcessGuideNavigationAgentの子。
拡張方法:
目的のステップ名を返す
ProcessGuideNavigationAgentの新しい子クラスを作成します。前に作成したナビゲーション エージェントを条件付きで返す
ProcessGuideNavigationAgentFactoryから派生する新しいクラスを作成します。コントローラー クラスの
navigationAgentFactory()メソッドを拡張して、前に作成したファクトリを返します。
既存のステップの UI で新しいコントロールを追加
拡張場所:
- このステップの
ProdProcessGuidePageBuilderの子。
拡張方法:
-
addDataControls()メソッドを拡張し、追加のコントロールを追加します。
既存のステップでのユーザー インターフェイスの全体的な修正
拡張場所:
-
ProdProcessGuideStepの子。
拡張方法:
ProdProcessGuidePageBuilderクラスの新しい子クラスを作成し、目的のユーザー インターフェイスを実装します。ステップ クラスの
pageBuilderName()メソッドを拡張して、前に作成したクラスのProcessGuidePageBuilderNameAttributeを返します。
ステップが完了と見なされたときにロジックを変更します。
拡張場所:
-
ProdProcessGuideStepの子。
拡張方法:
-
isComplete()メソッドを拡張して、追加のロジックを構築します。