この特集のトップページへ
Chapter 6:ビジネスロジックの設計

head2.gif 6.4.3 明細の処理
 さて,次に明細の処理を実装してゆく。Fig.6-72でも示したように,明細は明細情報テーブルに1つのレコードとして格納され,伝票と結び付けられる。

 ここでは伝票に明細を追加したり,編集したり,削除したりするのに必要なメソッドを実装してゆくことにする。

●明細の追加
 まずは明細の追加処理から考えてゆく。明細を追加するには,明細情報テーブル内に新しいレコードを作り,それを伝票テーブルのレコードと結び付ければよい。

 明細情報テーブルは,「3.2 データベーステーブルの設計」においてTable 6-16のように定義した。

Table 6-16 明細情報テーブル
フィールド名サイズNULL解説
ID数値型(オートナンバー)不可明細を識別するための唯一無二の番号
PRODUCTID数値型不可この明細の対象となる製品を示す製品番号。製品情報テーブルのIDフィールドに格納されているいずれかの値が格納される
NUMBER数値型不可注文された製品の数量
UNITPRICE金銭型不可製品の単価。通常は,製品情報テーブルのPRICEフィールドの値と同じものが格納される
PRICE金銭型不可価格。注文された個数(NUMBER)×製品の単価(UNITPRICE)が格納される
MEMO文字型80摘要
SLIPID数値型不可この明細を含んでいる伝票の伝票番号。伝票情報テーブルのIDフィールドに格納されているいずれかの値が格納される
MADEUSER文字型256不可この明細情報を登録したユーザーのアカウント名
MADEDATE日付型不可この明細情報を登録した日時
LASTUSER文字型256不可最終更新者のアカウント名
LASTDATE日付型不可最終更新日
DELETEDFLAGBoolean型削除されたかどうかのフラグ。Trueで削除されたことを,Falseで削除されていないことを示す

 
○明細レコードの追加
 Table 6-16を見るとわかるように,明細情報テーブルにレコードを追加するには,製品番号,数量,単価,価格,摘要,伝票番号という6つの情報が必要である。そこで,これら6つの情報を引数として受け取り,明細情報テーブルに新しいレコードを追加するメソッドを実装する。

 「6.1.2 データオブジェクト」でも説明したように,伝票追加情報テーブルを操作するメソッドは,DataObj.SlipDetailというコンポーネントに実装する。ここでは,DataObj.SlipDetailコンポーネントにAddRecordという名前のメソッドとしてList 6-123に示すように実装することにする。

○伝票の小計,消費税,合計の変更
 List 6-123に示したAddRecordメソッドを呼び出せば明細情報を追加できるわけだが,明細情報を追加したときには,伝票の小計,消費税,合計を再計算する必要がある。

 そこでまず,List 6-124に示すGetSubTotalメソッドをDataObj.Detailコンポーネントに実装する。

 List 6-124GetSubTotalメソッドは,第1引数に指定された伝票に結び付けられている明細の小計(税抜)を計算し,それを戻り値として返すものである。小計額を算出するため,19行目では次のようなSELECT文を実行している。

SELECT SUM(PRICE) As SUBTOTAL FROM 明細情報
 WHERE SLIPID=伝票番号 AND DELETEDFLAG=0

 なお,このSELECT文では,WHERE句にDELETEDFLAG=0を指定することで,削除ずみのレコードを含めないようにしている。もしこのWHERE句を付け忘れると,削除したはずのレコードの金額も小計に含まれてしまう。

 次に,List 6-125に示すSetTotalメソッドをDataObj.Slipコンポーネントに実装する。

 SetTotalメソッドは,第1引数から順に,伝票の伝票番号,小計(税抜),消費税,合計額(小計+消費税)を渡すと,その値を伝票レコードのSUBTOTALフィールド,TAXフィールド,TOTALフィールドに格納するというものである。

 SetTotalメソッドは,小計,消費税,合計の3つの値を引数として受け取るようになっている。しかし,小計のみを受け取り,消費税額と合計額はメソッド内で算出して設定させることも不可能ではない。だが,データオブジェクトの目的はデータベースを操作することにあり,演算することとは目的が異なる。特に,消費税額は将来的に消費税率の変更に伴って変更されるおそれがあり,変更されるたびにデータオブジェクトのプログラムを更新する結果となるのは避けたい。なぜなら,消費税額とデータベースの操作は何ら関係がないためである。消費税額などはビジネスコンポーネント側で計算し,その値をデータオブジェクトに渡し,データオブジェクトはその値を格納するだけという形態にしたほうが,消費税率の変更に伴う修正をビジネスコンポーネントだけに限定できるため,拡張性は高くなる。

 たとえば,消費税の端数処理をどうするかということを考えてみよう。消費税の端数処理をする場合,(1)伝票上は端数も記録し月次でまとめて請求書を作ったときに四捨五入する,(2)伝票上で端数を四捨五入する,という2つの方法が考えられる。どちらかの方法に統一してしまうのであれば問題ないが,業種によっては取引先ごとに(1)の方法と(2)の方法を使い分けるということもあり得る。その場合,データオブジェクトで消費税を計算するように実装してしまうと,データオブジェクト側で顧客情報テーブルから顧客の情報を参照する必要が生じるため,操作が複雑になりがちである。しかし,ビジネスコンポーネント側で消費税額を計算するようにしておけば,顧客情報テーブルを操作するDataObj.Productコンポーネントに顧客ごとの消費税を計算するメソッドを用意し,それとList 6-125で示したSetTotalメソッドとを組み合わせることで,簡単に対処できる。

○明細を追加するためのビジネスロジックの実装
 では,以上で作成してきたデータオブジェクトのメソッドを組み合わせてデータベース操作し,伝票に明細を加えるビジネスロジック側のメソッドを追加する。ここでは,このメソッドをBusiness.SlipコンポーネントにAddSlipDetailという名前で実装する(List 6-126)。

 List 6-126AddSlipDetailメソッドは,第1引数で指定された伝票に明細情報を付け加えるというものである。製品番号,数量,価格など,明細の情報は第2引数以降で指定されることになる。

 AddSlipDetailメソッドではまず,第2引数で指定された製品番号に相当する製品が存在するかどうかを確かめている(31〜36行目)。そして,引数に与えられた製品単価と製品価格(単価×数量)の両者がNullであれば,製品情報テーブルから取得した単価を利用する(39〜43行目)。この処理は本質的に不要ではあるが,もし定価販売するのであれば,製品番号と数量さえ指定すれば明細を追加できるようになるので,この機能があると便利である。

 そのあと,50〜52行目では対象となる伝票が削除されていないことを確認し,55〜57行目では伝票の状態がまだ承認待ちになっていないことを確認している。承認待ちでないことを確認する理由は,主に2つある。1つは,伝票がすでに発送されたものに対して明細を追加してしまうと,出荷された製品と伝票とのあいだで不整合が生じるからである。もう1つは,上司が承認したあとで伝票に明細を追加するというのは,業務プロセスとして許されないからである。

 また,68〜77行目では,伝票の起票者を調べ,起票者以外が明細を追加しようとしていないかどうかを確かめている。ただし,73行目にあるように,SalesManagerSalesAdminAllAdminという3つのロールに属するユーザーであれば,他人が起票した伝票にも明細を追加できるようにしてある。

 79行目以降は,実際に明細を追加する処理である。まず83行目でDataObj.SlipDetailコンポーネントのAddRecordメソッド(List 6-123)を呼び出し,明細のレコードを追加する。そのあと,GetSubTotalメソッド(List 6-124)を呼び出して,伝票に付随する明細の小計額を取得する。そして,取得した小計額から消費税額と合計額を算出し,DataObj.SlipコンポーネントのSetTotalメソッド(List 6-125)の引数に与える。その結果,伝票のSUBTOTALTAXTOTALという各フィールドの値が更新される。

 なお,上記の説明からもわかるように,この段階では製品の在庫が足りるかどうかをチェックしていない。製品の在庫が足りるかどうかは,伝票を起票するときではなく,承認を依頼するときにチェックすることにする。伝票の起票中に在庫の判断をし,ユーザーに明細のレコードを追加させないようにしてしまうと,在庫が足りない明細を含む伝票を作ることができず,結果として納期が不定な伝票(つまり在庫が揃い次第出荷という形の伝票)を作ることができなくなるためである。在庫の確認の具体的な処理内容については,「6.5 伝票の遷移」で説明する。

prevpg.gif Chapter 6 59/92 nextpg.gif