今回紹介するのは、トランザクションとマジックキーを使った応用編とも言える、親・子供・孫のすべてのレコードを一つの画面で一度に編集できるようにする方法です。
Magic Portals
(元記事はこちら)
Kevin Frank
2019/4/26
今回は、ある顧客のリクエストに対応するために最近使用しているデザインパターンを紹介します。リクエストというのは、親・子供・孫のすべてのレコードを、単一の”フラット化された”インタフェースを介して、表示および編集できるようにすることです。
デモファイル: magic-portals.zip (FM 16以降が必要です)
いくつかの補足情報
vender(仕入先)から受け取ったinvoice(請求書)は”payable(未払い金)”として入力されます。
…そして週に1回、venderごとにpayableを1件のcheck(小切手)にまとめる処理が行われます。
今回のデモでは、上で説明したことがすでに行われたと想定して、これから掘り下げようとしている手法を使う場面に進みます。
以下がリレーションシップグラフの関連部分です…
…ご覧のとおり、checkには1つ以上の関連するpayableがあり、各payableには1つ以上の関連するline item(別名payline)があります。
具体的な要件
#1. checkが発行された後で、元となるpayableデータを調整しなくてはいけない場合があります。当然ですが、checkの受取人、発行日、発行番号、金額は変更できません。しかし、ユーザは根拠となるpayableを調整できる広い自由度を持つ必要があります。具体的には以下が含まれます。
- payableのline itemの修正・追加・複製・削除
- payable全体の修正・追加・複製・削除
…しかし、当然ながら、最終的な合計はcheckの金額と一致させる必要があります。
#2. フラット化されたインタフェース: 複数レベルのデータを、シンプルなUIで表示および操作できるようにします。
#3. キーボードで操作できること: ユーザはキーボードから手を離さずに素早く処理を行うことを希望し、またリレーションに基づいて”レコード作成を許可”の機能を使ってポータルにデータを入力することに慣れています。payableに新しいline itemを作成するのに、一番下の空の行にtabで移動して入力を開始するので、それをサポートする必要があります。
#4. [Cancel]ボタンを押すとすべての変更を元に戻せること。ユーザが[OK]をクリックした場合にのみ変更が確定されること。ただし…
#5. ユーザが[OK]をクリックしたら、変更を検証すること。システムへゴミの侵入を許可したくありません。
#6. 最後に、処理はトランザクションで行うこと。つまり、ユーザが[OK]をクリックしたら、すべての変更はばらばらの順次ステップではなく単一のステップでコミットされること。(トランザクションモデルの詳細については、Jeremy Brownによるこの記事を参照してください。)
実際の画面
[check]タブに移動し、いずれかのcheckで[Edit]をクリックします。
新しい”ダイアログ”ウィンドウが表示されます…
このダイアログには以下のような特徴があります。
- 元のcheckのメモを追加または編集できる
- 新しいpayableを追加できる
- 既存のpayableを複製できる
- payableを削除できる(payableが1つしかない場合、このボタンはグレー表示される)
- payable内で行を複製できる
- 行を削除できる
- [Cancel]をクリックすると全ての変更が元に戻る
- [OK]をクリックすると変更が確定する(関連するすべてのpayableの合計額が元のcheckの金額と一致しない場合、このボタンはグレー表示される)
丸数字の2,3,4のところで”マジック”が起こります。しかしここで、今回の記事のタイトルが二重に嘘をついていることを告白しなくてはいけません。一つ目は、A. もう気づいていると思いますが、これらは実際にはポータルではありません。そして、B. 本当の魔法は使っていません。
しかし、少なくとも私にとってマジックのように思えるのが、ここをクリックすると…
…ポータルが一瞬で画面上に複製されるのです。
このウィンドウが(デバッグモードではなく)通常モードで表示されているときは、”Restricted(制限付き)”のカスタムメニューがロードされ、不注意によるミスを防ぐことができます。これはダイアログ形式のウィンドウなので、[OK]または[Cancel]をクリックしてこのウィンドウを閉じるまで、他のFileMakerウィンドウを操作することはできません。Checkレコードを元のウィンドウにロックして、この処理の間はそのままにしたいので、このモダリティは重要です。
その他の2つの興味深い点:
- 編集可能なフィールドを行をまたいで、tabで次に、shift-tabで前に移動できます。これはあたかも本物のポータルのようです。
- リレーションに基づいた”レコードの作成を許可”の設定がされた本物のポータルと同じく、一番下の空の行にデータを入力すると、フィールドから出る時に新しい空の行が一番下に作成されます。
舞台裏
以下がテーブル定義です。
以下がリレーションシップグラフの全体です。
以下がレイアウトです。ユーザにポータルを操作している錯覚を起こさせるために設定したスクリプトトリガを表示しています。このレイアウトはtemppaylineテーブルに基づいており、実態としてはid_payableを小計パートとしたブラウズモードの集計レポートです。
ユーザーが[Edit]をクリックした場合
- [レコードを開く]コマンドを発行して、checkレコードの所有権を取得しようと試みるエラーが発生した場合、現在レコードを編集している人を示すダイアログを表示して、元に戻る。そうでなければ…
- 一時ウィンドウでpayableと関連のline itemを空のテーブルにインポートしてから、一時ウィンドウを閉じる(その間、checkレコードは元のウィンドウでロックされたままになる)
- 新しいダイアログ形式のウィンドウで、上に示したレイアウトを使用して、新しくインポートされたtemppaylineレコードを表示する
- payableごとに空のtemppaylineレコードを1つ生成する(最下部の空のポータル行をシミュレートするため)
- temppayline::id_payableを昇順、temppayline::flag_emptyを降順でソートする
ユーザが[Cancel]をクリックした場合
- 編集ウィンドウを閉じる
- 元のウィンドウを選択
- レコードの復帰でチェックを解除する
ユーザーが[OK]をクリックした場合
- データを検証する
- 空の行を削除する
- (temp)payableと(temp)paylineのデータをJSON形式に変換して変数に入れる
- 編集ウィンドウを閉じて元のウィンドウを選択する(注意: このウィンドウではcheckレコードが”開いて”いる)
- トランザクション処理によってデータを更新する
- 買掛金ポータルから元の関連するpayableとpaylineレコードを削除する
- マジックキー手法を使用して、JSONを新しい一連のpayableレコードとpaylineレコードに書き出す
- チェックレコードをコミットする
デバッグモードで実行する
[Debug]のチェックボックスをチェックすると、[Edit]ボタンをクリックしたときの動作が次のように変わります。
- インポートが行われる一時ウィンドウは、画面外ではなく画面内に描画される。表示は非常に速いため、目視するにはスクリプトデバッガでステップ実行する必要がある
- 編集ウィンドウは、ダイアログ形式のウィンドウではなく、ドキュメント形式のウィンドウとして呼び出される
- “Restricted”カスタムメニューセットはインストールされない
- 2つの”一時”テーブルがそれぞれのウィンドウに表示される
まとめ
私は冒頭で、このテクニックは親・子供・孫のデータを編集することを可能にすると述べました。今回のデモでは、意図的にcheck(つまり親)データでNoteフィールドだけを編集可能に設定しました。それは、今回のシナリオでは、それ以外のCheckデータは変更禁止だったためです。しかし、このテクニックで親・子供・孫レコードの本格的な作成や編集を許可するように適応させることも、もちろん可能です。
このテクニックの他の用途には、以下のようなデータのレビュー/作成/更新などがあります。
- プロジェクトごとに分類された請求可能な時間エントリ
- ある期間の従業員経費の提出
- ある期間またはある仕入先の購買発注
- etc./etc./etc.
これは、空の(scratch)テーブル(2つ)とトランザクションモデルの両方を使用した”ハイブリッド”な手法で、これが私の初めての実装です。おそらく改善の余地があると思うので、提案をお待ちしています。