見積依頼機能の記事で、見積書のPDFは入れていないと書きました。見積の実体は受注なので、納品書の出力を複製すれば出せます、とも。

その複製をやってみたら、思っていたより素直に済んだ部分と、思っていたより手強い部分がはっきり分かれました。

作るもの

管理画面の受注編集に「見積書を出力」を足します。納品書の隣です。

管理画面の受注編集の出荷情報。「注文者情報をコピー」「納品書を出力」の隣に「見積書を出力」のボタンが並んでいる

押すと納品書と同じ入力画面が開いて、そこから見積書のPDFが落ちてきます。

作るものは4つです。

つくるもの役割
PDFを作るクラス納品書のものを継承して、違うところだけ差し替える
管理画面のコントローラ入力画面とダウンロード
入力画面のテンプレート納品書のものをコピーして送り先を変える
受注編集のボタン納品書の隣に1つ足す

本体には触らない

2020年にセット商品の内訳を納品書に出す記事を書いたとき、こう書いています。本体のサービスクラスを直接編集するしかない、アップデートで消えるので Git で管理してください、と。

今回は触りません。PDFを作るクラスは final ではなく、描画のメソッドがすべて protected です。管理画面のコントローラにも注入されています。継承したクラスを app/Customize に置いて、自分のルートから呼べば済みます。 納品書の出力もそのまま残ります。

これが 4.4 で変わったのかと思って 4.0 のソースを見に行きました。変わっていませんでした。 2020年の時点でこのクラスは final ではなく、描画のメソッドは protected で、コントローラにも引数で渡されています。当時から継承できたということです。

言い訳をすると、やりたいことが違いました。6年前は納品書そのものに1行足したかった。本体が出す帳票の中身を変えるなら、本体が使っているサービスを差し替えないといけません。 今回は納品書を残したまま別の帳票を増やすので、継承したクラスを自分のルートから呼ぶだけで済みます。

前者も、いまなら本体を編集せずにサービスの定義を差し替えるほうを選びます。6年前の自分は手が早すぎました。

差し替えたところ

継承したクラスで上書きしたのは4つです。

上書きしたもの何をしたか
PDFを作る入口発行日を受け取って覚えておく
備考を描くメソッド備考の前に有効期限の欄を足す
フッター「作成日」を「有効期限」に変える
ファイル名nouhinsyo-No11.pdfmitsumori-No11.pdf に変える

有効期限は、入力画面で指定された発行日から30日後にしました。定数を1つ持たせているだけなので、店舗の運用に合わせて変えられます。

タイトルは上書きしていません。入力画面から渡された文字列をそのまま描く作りになっているので、コントローラ側で既定値を「御見積書」にするだけで済みます。メッセージの1〜3行目も同じです。ここは本体がよくできています。

出てきたのがこれです。

見積書のPDF。タイトルは御見積書、宛名は株式会社スイーツ商会・見積 太郎 様。ただし金額欄の見出しが「総合計金額」、明細の見出しが「お買上げ明細」、その下が「[ご注文日]」「[注文番号]」のままになっている。明細表の最終行も「請求金額」

宛名も明細も金額も合っています。有効期限も出ました。

ただ、見積書として人に出せるかというと出せません。

文言が背景PDFに印刷されている

「お買上げ明細」「[ご注文日]」「[注文番号]」「総合計金額」の4つは、コードのどこを探しても見つかりません。

本体の納品書は、A4の枠だけを作った背景PDFを読み込んで、その上に値を描いています。背景は html/template/admin/assets/pdf/nouhinsyo.pdf です。このファイルからテキストを抜き出すと、ちょうどこの4つが出てきます。

つまり、この4語は画像に近い扱いです。コードでいくら上書きしても変わりません。

これは納品書としては合理的です。罫線も見出しも一度デザインしてしまえば、コードは値を置くだけで済みます。ただ、書式の違う帳票を作ろうとすると、背景ごと差し替えることになります。

背景は差し替えられる

幸い、そこには継ぎ目があります。ページを追加するメソッドが protected なので、そこを上書きして、ページを追加する直前に読み込む背景を自分のファイルに変えられます。PDFを作る入口を丸ごと書き直す必要はありません。

見積書用の背景を作って差し替えると、こうなります。

背景を差し替えた見積書のPDF。見出しが「お見積り金額」「お見積り明細」「[お見積り日]」「[お見積り番号]」に変わっている。ただし金額と日付、番号の値が見出しと重なった位置に描かれていて、行がずれている

見出しは見積書になりました。代わりに値の位置がずれています。

値を描く座標は、納品書の背景に合わせて数値で埋め込まれています。日付は上から125ミリの位置、注文番号は135ミリの位置、といった具合です。背景の見出しを動かすと、値だけが元の場所に取り残されます。

背景を作り替えるなら、描画のメソッドも上書きして座標を合わせ直す。ここまでやって、ようやく見積書です。

どこまでが継承で済むか

やってみて分かった線引きです。

やりたいこと手数
タイトル、メッセージコントローラで既定値を変えるだけ
ファイル名、フッター、備考欄メソッドを1つずつ上書き
背景の図案背景PDFを作り、ページ追加のメソッドを上書き
値の位置描画のメソッドを上書きして座標を書き直す
明細表の中の「商品合計」「請求金額」明細を組み立てるメソッドを丸ごと上書き

下の2つが重い。明細表を組み立てているメソッドは150行ほどあって、税率ごとの集計も複数配送の分岐も入っています。「請求金額」を「お見積り金額」に変えたいだけでも、この150行を抱えることになります。

上3つで足りるなら継承は割に合います。 下2つに手を出すなら、いっそ帳票だけ別のライブラリで作ったほうが後々楽かもしれません。本体の集計ロジックは受注エンティティから取り直せます。

割り切ったところ

出荷単位で出しています。 本体の納品書は出荷を1件ずつPDFにする作りで、入力画面も出荷IDを受け取ります。見積書は本来なら受注1件で1枚のはずですが、そこは合わせました。複数配送の受注だと出荷の数だけ見積書が出ます。

明細表の「請求金額」がそのままです。 上に書いた150行の理由です。見積書に「請求金額」と書いてあるのは、正直よくありません。運用に乗せるなら直すことになります。

単価が税込です。 本体の納品書がそう作られています。見積書は税抜で並べて最後に消費税を足す書式が多いので、ここも直す候補です。

押印欄がありません。 背景PDFに枠を足せば置けます。今回作った背景は見出しを入れ替えただけのものです。

見積のステータスと連動していません。 受注編集から出せるので、見積依頼中でない受注からも見積書が出ます。見積用のステータスのときだけボタンを出すなら、テンプレート側で条件を付けてください。

会員グループ管理を入れている場合

金額は受注に入っている値をそのまま印字するので、会員グループ価格管理アドオンで出し分けた卸価格が、そのまま見積書の単価になります。PDF側で価格を計算し直してはいません。

取引先ごとに掛け率が違っても、見積書には確定した金額が並びます。見積依頼機能と組み合わせるなら、卸価格を土台に案件ごとの値引きを入れて、その結果を見積書にする流れになります。

B2B サイト全体でどこまでが標準・プラグインで、どこからが作るものになるのかは、B2Bサイト全体の線引きにまとめました。