こんにちは、こんです🦊
今日は、Streamlitで開発している納品書自動生成アプリにおいて、細かいけれど見逃せない「帳票のズレ」や「見た目の整列性」に関する修正を行いました。
一見するとただのPDF出力なのですが、実際に印刷・確認・運用される帳票であるがゆえに、1pxのズレや数字の桁揃えが実務に与える影響は大きいと感じた一日でした。
🧭 取り組んでいる背景
この開発は、業務現場の「納品書・出荷伝票・インボイスなどを手入力で整える作業を自動化したい」というニーズから始まりました。
具体的には以下のような流れを自動化しています:
Excel形式で送られてくる納品情報を読み取り
PDFの納品書を自動生成
見た目はテンプレートに準拠し、帳票としてそのまま使える状態で出力
使用しているのは、Python + Streamlit + fpdf2。
UIはWebアプリ化されており、誰でもアップロード・PDF出力ができる仕様です。
💡 今日のテーマ:「整列性」と「わかりやすさ」を両立する出力ロジック
🧪 課題1:合計行がズレる
PDFの明細表の下に「合計数量」「合計金額」を表示しようとした際、表示位置が1列分ずれて右に寄ってしまう問題が発生しました。
原因は、fpdf.table() で描画されたテーブルと、手動で pdf.cell() を使って描画する合計行とで、X座標の基準位置がずれていること。
理論上は pdf.l_margin や pdf.get_x() を使えば揃うはずですが、実際は fpdf.table() が内部的に描画位置を持っており、そのズレを正確に補正する方法が明文化されていないのが実情です。
結論として、今回は暫定的に x = 3 というハードコードで座標を調整しました。
📝 実務的な学び:「なんで3なのか」は重要ではない。見た目が帳票として自然かが優先される。
🧪 課題2:単価の動的切り替え
納品書に記載される明細のうち、実商品か販促物かによって**無償提供品(=単価0円)**かどうかを判断。
対応としては、以下のようなコードを使って「形態」によって単価を分岐:
invoice_df["単価"] = invoice_df["種別"].apply(
lambda x: 0 if str(x).strip() in ["商品", "販促"] else 525
)
これは非常にシンプルなロジックですが、「列ごとの分岐条件とそれに基づく表示変更」はPDF帳票処理で頻出パターンです。
その意味で再利用性の高い記述だと感じました。
🧪 課題3:明細テーブルの整列性と桁揃え
PDFで出力する明細表の中で、「文字列」は左寄せ、「数値」は右寄せにすることで読みやすくするのは基本中の基本ですが、ヘッダーとデータ行で揃え方を分けたいという場面が出てきました。
今回は以下のように、fpdf.table() の text_align をデータ行用に定義し、ヘッダー行のみ個別に align="L" を明示して出力:
detailTBalignments = ("LEFT", "LEFT", "LEFT", "LEFT", "RIGHT", "RIGHT", "RIGHT")
if i == 0:
row.cell(str(cell), style=header_style, align="L") # ヘッダーのみ左寄せ
else:
row.cell(str(cell))
加えて、金額や数量などの数値項目には桁区切り(,)を追加することで、視認性と確認性の両方を高めました。
f"{int(row['金額']):,}"
✨ 汎用的に活かせるポイント
PDF出力の微調整(とくに座標)はロジックよりも実際の出力を信じよ
明細表では align=RIGHT を使うだけで業務精度が一段上がる
データによって出力内容を切り替える if文や apply() の書き方はパターン化しておくと便利
日本語帳票では「見やすいフォントサイズ」「適切なカンマ」「整列」こそが信頼感につながる
📌 明日以降の方針
合計行出力のズレを根本から解消する「X座標の基準点管理」の共通関数化
明細テーブルの構成要素(列幅、align、ヘッダーラベル)を辞書化し、可読性と再利用性を上げる
他帳票(インボイス、注文書)にも同じ整列・カンマ処理を展開して「統一された出力体験」へ
🧠 ハッシュタグ
#100日チャレンジ
#業務改善
#帳票整列問題
#Python自動化
#fpdf2
#Streamlit開発記録
#PDF出力チューニング
#DXの泥臭いところ
#納品書整形戦争