610 likes | 784 Views
Microsoft Office InfoPath 2003 を用いた SAP フロントエンド開発の概要. ビジネスプロダクティビティソリューション本部 マイクロソフト株式会社. Agenda. InfoPath 2003 の概要 サンプル構築環境の確認 検索モードの作成 更新モードの追加 おわりに Appendices. InfoPath 2003 の概要. リッチでダイナミックなフォームの作成を可能にし、正確な情報を効率的に収集することができる Office アプリケーション. 柔軟かつ効率的に正確な情報を収集
E N D
Microsoft Office InfoPath 2003を用いたSAPフロントエンド開発の概要 ビジネスプロダクティビティソリューション本部マイクロソフト株式会社
Agenda • InfoPath 2003 の概要 • サンプル構築環境の確認 • 検索モードの作成 • 更新モードの追加 • おわりに • Appendices
InfoPath 2003 の概要 リッチでダイナミックなフォームの作成を可能にし、正確な情報を効率的に収集することができる Office アプリケーション 柔軟かつ効率的に正確な情報を収集 時間の削減、入力エラーの無い正確な情報収集、再入力の排除 人、情報、プロセスをより効率的に結合 既存のシステムとデータを最大限に有効活用し、意思決定を支援 容易なフォームソリューションの構築と高いメンテナンス性 ビジネスプロセスの変化への迅速な対応、TCO 削減
作成するフォームテンプレート • SAP CRMのトランザクション“CRMD_BUS2000111”の一部機能を抜粋したフォームを作成 • 案件を検索する「検索モード」と、特定の案件を更新する「更新モード」を実装 <検索モード> <更新モード>
サンプルフォーム構築環境 • クライアント コンピュータ • Windows XP Professional (SP1 以上)または Windows 2000 (SP3 以上) • Internet Explorer 6.0 (SP1 以上) • Microsoft Office InfoPath 2003 SP1または Microsoft Office Professional Enterprise Edition 2003 SP1 • サーバー コンピュータ • mySAP CRM Server 4.0 が正常稼動している環境※サンプル検証環境は、次の通り • mySAP CRM Server 4.0 • mySAP CRM Middleware Server
(参考) SAPモジュールの要件 • SAPサーバーと InfoPath 2003 は、Webサービスを介して通信を行う • Webサービス(SOAPでの通信)に対応するSAPモジュールは次の通り • カーネル 4.0B 以降のR/3、APO、SRMなど、ABAPアーキテクチャのもの • 「SAP .NET Connector」 を利用して、Webサービスを別途構築要 • カーネル 6.2 以降 • WebAS の機能により、Webサービスを設定可能
BAPIのリモート接続有効化 • “/nse37” で、各BAPIの「属性」タブ内の「処理タイプ」が、「リモート可能モジュール」になっていることを確認 • 「リモート可能モジュール」になっていない場合、 “sicf”より、「bc」ノードのコンテキストメニューから「サービス有効化」を選択
使用する BAPI • SAP CRMからの各種データ取得 / 更新の際には、次に挙げる BAPI を、SOAPプロトコルを利用して呼び出す(Webサービスとしてコール) • CRM_WAP_OPP_GET_LIST案件情報を取得する際に利用 • CRM_WAP_OPP_SAVE案件情報を更新する際に利用(※新規登録は除く) • CRM_WAP_GET_PHASE_LIST案件のフェーズ一覧を取得する際に利用(※セールスサイクル“1”「一般案件」に割り当てられているフェーズが取得対象) • CRM_WAP_GET_OPP_POSSIBLE_STAT案件のステータス一覧を取得する際に利用
WSDLの確認 (1/2) • “/nse80”を実行 • 「WebServiceBrowser」をダブルクリック (※ツリーに表示されていない場合には、「BSPアプリケーション」を選択し、「WEBSERVICEBROWSER」と入力後、Enter) • BSPアプリケーション照会画面の「テスト」アイコンをクリックし、SAPログオン時のユーザ名とパスワードを入力して、「OK」ボタンを押す
WSDLの確認 (2/2) • Web Service Browser画面の「By Name」欄に、使用するBAPIの名前(「CRM_WAP_OPP_GET_LIST」等)を入力後、Enter • Result欄の「wsdl」リンクをクリック • ブラウザに表示されたWSDLのURLを、アドレスバーから取得し、メモ帳等でテキストファイルに記入(URLは個々の環境により異なる)
デザインの開始 プライマリデータソースの修正 レイアウト設計 検索モード作成手順の概要 データ接続の追加 フォームテンプレートのテスト フォームテンプレートの発行 ※順不同で繰り返し
デザインの開始 • 「データ接続から新規作成」を選び、フォームのデザインを開始 • 案件情報の取得Webサービス「CRM_WAP_OPP_GET_LIST」をプライマリデータソース(データの受信)に指定
プライマリデータソースの修正 (1/4) • WSDLから自動生成されたスキーマ内の要素のうち、一部の要素の定義が必須項目となってしまうため、修正が必要 読み取り専用となっているためInfoPathのUIからは修正不可 必須項目は、赤アスタリスクで示されるが、実際のBAPI呼び出し上は必須ではない
BAPIの項目を定義したスキーマ プライマリデータソースの修正 (2/4) • 赤アスタリスク(*)の付いている項目をチェック • [ファイル] - [フォーム構成ファイルの取り出し] を実行し、フォームの構成ファイルを展開(その後、InfoPathを一旦終了) • 展開されたファイルの中から、自動生成されたBAPIのスキーマ情報が格納されたファイルを探す(“schema1.xsd”等の拡張子“.xsd”のファイル) ビュー(xsl) スキーマ(xsd) フォーム定義manifest(XSF) ロジック(DLL) デフォルトデータ(xml) Schema1.xsd 等
プライマリデータソースの修正 (3/4) • 次の型の要素を中心に、テキストエディタでチェック • xsd:decimal , xsd:date , xsd:base64Binary • 1で控えたノードと同じなら、nillable=“true” 属性を追加 <例> ~ 前略 ~ <xsd:complexType name=“CRMT_REPORT_INBOXLIST”> <xsd:sequence> ~ 中略 ~ <xsd:element name=“EXP_REVENUE” minOccurs=“0” nillable=“true”> <xsd:simpleType> <xsd:restriction base=“xsd:decimal”> <xsd:totalDigits value=“15”/> <xsd:fractionDigits value=“2”/> </xsd:restriction> </xsd:simpleType> </xsd:element> ~ 中略 ~ </xsd:sequence> </xsd:complexType> ~ 後略 ~ これを追加
フォーム定義manifest(XSF) プライマリデータソースの修正 (4/4) • 2で取り出したファイル中の“manifest.xsf”を右クリックし、「デザイン」を実行 (InfoPathが起動) • データソース作業ウィンドウにて、必須項目指定が解除されていることを確認 • InfoPathフォームを保存 右クリック InfoPath起動 必須項目指定が解除されていることを確認
フォームで使用するノードの確認 queryFields dataFields
基本的なレイアウト設計手順 • タイトル付きの表を挿入 • データソース作業ウィンドウから、配置したいノードを含むグループをドラッグ&ドロップ(セクションの挿入) • 各セクションに含めたいノードのレイアウト用に、レイアウト用の表を挿入 • データソース作業ウィンドウから、配置したいノードを、前項で挿入した表内にドラッグ&ドロップ(コントロールの挿入) • コントロール種別の変更、セカンダリデータソースの割り当て • 各ノードのラベル名を調整(日本語ラベルへの書き換え等) • ボタンコントロール等の配置 • 全体レイアウトの調整、配色等
ドロップダウンリストボックスの設定 • ドロップダウンリストボックスコントロールとして配置するノードと設定値
検索モードのテスト 実際にフォームを動かしてテスト
レイアウト設計(ノードの追加等) 条件付書式の設定 データ接続(更新用)の追加 更新モード追加手順の概要 動作規則の設定 / スクリプトの追加 フォームテンプレートのテスト フォームテンプレートの発行 ※順不同で繰り返し
更新モード設計上のポイント (1/2) • 検索モード実行後に抽出された案件の中から、更新したい案件の「案件概要」部分をクリックすることにより、更新モードに移行 <検索モード> <更新モード> クリック
更新モード設計上のポイント (2/2) • Webサービスへのデータ送信のポイントは、受信用データ接続として、送信を設計すること • 送信用データ接続では、戻り値を処理できない • Webサービスが、InfoPathからの引数を受け取れた時点で、 全て「成功」の扱いになるだけ • 受信用データ接続を使えば、戻り値を処理可能 • クエリの実行 = 送信処理の実行 • クエリの結果 = 戻り値 • データ接続設定時の、「フォームを開くとき自動的にデータを取得する」はオフに設定 • 送信対象となる項目値を、データ接続「CRM_WAP_OPP_SAVE」の「queryFields」にコピーし、クエリを実行
更新モード切り替え処理の実装 (1/2) • クリックされた案件の“GUID”を取得し、検索条件(プライマリデータソースの「queryFields」)の“P_GUID”にセット • クエリの実行(“GUID”が特定されると、単一の案件のみ抽出される) • ノート欄から不要な行を削除 • いずれもスクリプト(コーディング)により実装(後述の Script Cを参照)
更新モード切り替え処理の実装 (2/2) • 画面の書き換え • 「条件付書式」を利用して設定 • 案件情報の各項目は、検索モードでは、読み取り専用に設定 • “P_GUID”が空白のとき、次のコントロールを読み取り専用に設定すれば OK案件概要,見込終了日,受注見込,フェーズ,ステータス,見込販売額(※顧客名は常に読み取り専用に設定) • 案件情報のノート欄は、更新モードでのみ表示されるように設定 • “P_GUID”が空白のとき、次のノードに対応するセクションを非表示に設定すれば OK/dfs:myFields/dfs:dataFields/s0:CRM_WAP_OPP_GET_LIST.Response/ET_TEXT
データ更新処理の実装 (1/2) • 引数のセット(非繰り返し項目) • 「データ更新」ボタンに「動作規則」として設定 • 「フィールドの値を設定する」として、次の通りに動作を追加
データ更新処理の実装 (2/2) • 引数のセット(繰り返し項目) • 「データ更新」ボタンにスクリプトにより実装(後述の Script Dを参照) • クエリの実行 • 「データ更新」ボタンにスクリプトにより実装(後述の Script Bを参照) • 戻り値のハンドリング • 「データ更新」ボタンにスクリプトにより実装(後述の Script Eを参照) ※「ボタンのプロパティ」に、「動作規則」と「フォームのコードを編集」を同時設定した場合には、「動作規則」が先に実行される
Tips: 戻り値のハンドリング • 処理内容によって使い分け… • 次のような場合は、「動作規則」の設定で十分 • 戻り値に応じて適切なメッセージボックスを表示する • 戻り値に応じて他のフィールドに値をセットする • 戻り値をきめ細かくハンドリングしたい場合には、「データの入力規則」の設定を考慮 • コーディングが必須となるため、手間は掛かるが、ある意味、「何でもできる」 • 戻り値フィールドは、基本的に読み取り専用にするか、そもそもフォームに配置しない
Script A:変数及び関数定義 (1/2) (※ネームスペース定義部分は省略) var gdomTLINE; function getNodeList(xpath) { if (typeof(xpath) == "string") return XDocument.DOM.selectNodes(xpath); else return xpath; } function count(xpath) { var xmlNodeList = getNodeList(xpath); if (xmlNodeList) return xmlNodeList.length; else return -1; } ※本サンプルにおけるスクリプト記述は、JScript を利用
Script A:変数及び関数定義 (2/2) function CreateNode(dom, strNodeName, strNodeValue) { var objNewNode = dom.createElement(strNodeName); if (strNodeValue) objNewNode.text = strNodeValue; return objNewNode; } function CloneNode(dom, strNodeName, strNodeValue) { var objNewNode = dom.selectSingleNode(strNodeName).cloneNode(false); if (strNodeValue) { objNewNode.text = strNodeValue; } return objNewNode; }
Script B:フォーム読み込み時と 検索ボタンクリック時のイベント function XDocument::OnLoad(eventObj) { // CloneNode 関数実行用に保存 gdomTLINE = XDocument.GetDOM("CRM_WAP_OPP_SAVE") .getElementsByTagName("IT_TEXT").item(0).cloneNode(true); } function btnQuery::OnClick(eventObj) { XDocument.DOM.selectSingleNode("/dfs:myFields/dfs:queryFields/ s0:CRM_WAP_OPP_GET_LIST/P_GUID").text = ""; XDocument.Query(); }
Script C:更新モードへの切替え (1/2) function XDocument::OnContextChange(eventObj) { if (eventObj.Type == "ContextNode" && XDocument.DOM.selectSingleNode("/dfs:myFields/dfs:queryFields/ s0:CRM_WAP_OPP_GET_LIST/P_GUID").text == "") { var oContextNode = eventObj.Context; if (oContextNode.nodeName == "DESCRIPTION") { var strGUID = oContextNode.parentNode.selectSingleNode("GUID").text; var oITEM = getNodeList("/dfs:myFields/dfs:dataFields/ s0:CRM_WAP_OPP_GET_LIST.Response/ET_OPP/item"); var oGUID = getNodeList("/dfs:myFields/dfs:dataFields/ s0:CRM_WAP_OPP_GET_LIST.Response/ET_OPP/item/GUID"); for (var i = 0 ; i < count(oITEM) ; i++) { if (oGUID[i].text == strGUID) { var idx = i; } } (※次ページに続く)
Script C:更新モードへの切替え (2/2) (※前ページからの続き) var oET_GUID = getNodeList("/dfs:myFields/dfs:dataFields/ s0:CRM_WAP_OPP_GET_LIST.Response/ET_GUID/item/GUID"); XDocument.DOM.selectSingleNode("/dfs:myFields/dfs:queryFields/ s0:CRM_WAP_OPP_GET_LIST/P_GUID").text = oET_GUID[idx].text; XDocument.Query(); // 「ノート」欄のノードリストの先頭から、不要なノードを削除 var oET_TEXT = XDocument.DOM.selectSingleNode("/dfs:myFields/ dfs:dataFields/s0:CRM_WAP_OPP_GET_LIST.Response/ ET_TEXT"); var oITEM = getNodeList("/dfs:myFields/dfs:dataFields/ s0:CRM_WAP_OPP_GET_LIST.Response/ET_TEXT/item"); if (oITEM[0].selectSingleNode("TDFORMAT").text == "") { oET_TEXT = oET_TEXT.removeChild(oITEM[0]); } } return; } }
Script D:案件情報の「ノート」欄の セカンダリデータソースへの転記 function updateTLINE() { var objITEMNode = null; var objTDFORMATNode = null; var objTDLINENode = null; var oITEM = getNodeList("/dfs:myFields/dfs:dataFields/s0:CRM_WAP_OPP_GET_LIST.Response/ET_TEXT/item"); var oTDFORMAT = getNodeList("/dfs:myFields/dfs:dataFields/ s0:CRM_WAP_OPP_GET_LIST.Response/ET_TEXT/item/TDFORMAT"); var oTDLINE = getNodeList("/dfs:myFields/dfs:dataFields/ s0:CRM_WAP_OPP_GET_LIST.Response/ET_TEXT/item/TDLINE"); var nodeTLINE = XDocument.GetDOM("CRM_WAP_OPP_SAVE").selectSingleNode("/dfs:myFields/ dfs:queryFields/s0:CRM_WAP_OPP_SAVE/IT_TEXT"); var nodeITEM = XDocument.GetDOM("CRM_WAP_OPP_SAVE").selectNodes("/dfs:myFields/ dfs:queryFields/s0:CRM_WAP_OPP_SAVE/IT_TEXT/item"); nodeITEM.removeAll(); for (var i = 0 ; i < count(oITEM) ; i++) { objITEMNode = CloneNode(gdomTLINE, "item"); objITEMNode.appendChild(CloneNode(gdomTLINE, "item/TDFORMAT", oTDFORMAT[i].text || "")); objITEMNode.appendChild(CloneNode(gdomTLINE, "item/TDLINE", oTDLINE[i].text || "")); nodeTLINE.appendChild(objITEMNode); } }
Script E:データ更新処理 function btnUpdate::OnClick(eventObj) { updateTLINE(); XDocument.DataObjects("CRM_WAP_OPP_SAVE").QueryAdapter.Query(); // 戻り値が“006”なら、SAP CRM 側データの更新成功 var nodeRETURN = XDocument.GetDOM("CRM_WAP_OPP_SAVE").selectNodes("/dfs:myFields/ dfs:dataFields/s0:CRM_WAP_OPP_SAVE.Response/RETURN/item"); if (nodeRETURN[1].selectSingleNode("NUMBER").text == "006") { // 「フォームの送信」に設定されている送信処理も併せて行いたい場合には、下の行のコメントを解除 // XDocument.Submit(); XDocument.UI.Alert("データの更新が完了しました。"); } else { XDocument.UI.Alert(nodeRETURN[1].selectSingleNode("MESSAGE").text); } }
更新モードのテスト 実際にフォームを動かしてテスト
おわりに • Microsoft Office InfoPath 2003 を用いたSAP フロントエンド開発のメリット • エンドユーザのニーズや、使う状況に応じたフロントエンドアプリケーションの開発を容易に実現 • Webサービスのコールをウィザードベースで設定可能な他、多くのロジックをコーディングレスで実装可能 開発者 / エンドユーザ 双方の皆様方に多くのメリットをご享受いただける Microsoft Office InfoPath 2003 を、是非ご活用下さい。
Appendix-1 InfoPath 2003 におけるロジックの実装
ロジックの実装手段 高度なロジック • コーディングによるロジックの実装 マネージド コード:VB.NET / C# スクリプト:VBScript / JScript 計算 入力規則 動作規則 条件付書式 • プロパティ設定によるロジックの実装 多くのフォームはノンコーディングでロジックの実装が可能 入力規則 • XML スキーマレベルでのチェック
InfoPathのオブジェクトモデル Application Windows XDocuments User Window XDocument View Errors MailEnvelope DOM TaskPanes DataObjects CommandBars
XML DOM と XPath によるノード参照 XML DOM sales XDocument.DOM.selectSingleNode(“/ns:sales”) • 名前空間を利用 • 全てのノードは名前空間を持つ • ns : 名前空間の省略名 • DOMに対するメソッド • SelectSingleNode(“XPath”) • SelectNodes(“XPath” ) • text プロパティを利用 items item price ...selectSingleNode (”/ns:sales/ns:items/ns:item/ns:price”).text
InfoPathのイベント (1/2) • フォームイベントアプリケーションの状態やユーザーのアクションに応答 • データの入力規則XML Document Object Mode (XML DOM)に対して行われた変更に応答
Appendix-2 フォームテンプレートのセキュリティと展開
オブジェクトモデル メンバのセキュリティ レベル • オブジェクトモデルのメンバ(プロパティやメソッド)の悪用を防ぐためにオブジェクトモデルのメンバを使用できる展開方法と場所を規定(3つのセキュリティレベル) • (例)XDocument オブジェクトの SaveAs メソッドを利用するとファイルシステムの任意の場所にデータの書き込み可能 • SDKで提供されるオブジェクトモデル リファレンスに各メンバのセキュリティレベルが記載されている
フォームテンプレートのセキュリティ レベル (1/2) • フォームテンプレート内で使用されている機能とフォームテンプレートの配布場所・配布方法に基づいて規定される3つのセキュリティレベル • 既定では「制限あり」または「ドメイン」のどちらかのセキュリティレベルが自動的に選択 • 「ドメイン」は、Internet Explorer で定義されたセキュリティゾーンの設定と連動 • 完全信頼済みのフォームテンプレートを作成する場合や、手動で設定する場合は、「ツール」→「オプション」→「セキュリティ」タブから設定。「デザインに基づいて自動的にセキュリティ レベルを設定」をオフにして、3つから選択