どんな場面で使う?
- 月末の見積書大量作成: 顧客ごとの見積書を毎月20〜30件まとめて作成する営業事務の定型業務
- テンプレートへの差し込み転記: 一覧表のデータをテンプレートに1件ずつ手入力している作業の自動化
- 連番管理の自動化: 見積番号や納品番号の採番を手動で管理していて、番号の重複や飛びが起きている場合
- PDF納品: 見積書をPDFに変換してフォルダに保存し、メールに添付して送る一連の流れを効率化
- 納品書・請求書への横展開: 見積書と同じ仕組みで納品書や請求書のテンプレートも自動作成したい場合
—
請求書の自動作成については 【VBA】請求書を自動作成する方法 で解説している。見積書と請求書をセットで自動化すると、月末の帳票作業が大幅に楽になる。
—
完成イメージ(Before / After)
Before(実行前)
「一覧表」シートにデータが入っている。「テンプレート」シートは空のひな形。
【一覧表シート】
| A(顧客名) | B(品目) | C(数量) | D(単価) | E(備考) |
|-------------|-------------------|----------|-----------|------------|
| 山田商事 | Webサイト制作 | 1 | 300000 | 初回案件 |
| 鈴木工業 | システム保守(月額) | 12 | 50000 | 年間契約 |
| 田中建設 | サーバー構築 | 1 | 500000 | |
After(実行後)
一覧表の各行から見積書シートが自動作成され、PDFとして保存される。
C:\見積書出力\
├── EST-001_山田商事_見積書.pdf ← 自動生成
├── EST-002_鈴木工業_見積書.pdf ← 自動生成
└── EST-003_田中建設_見積書.pdf ← 自動生成
—
実行前の準備
バックアップを取る
マクロを実行する前に、Excelファイルをコピーしてバックアップを取ること。テンプレートシートの複製やデータ転記を行うため、万が一に備える。
Excelをマクロ有効ブック(.xlsm)で保存する
- Excelブックを開く
- 「ファイル」→「名前を付けて保存」
- ファイルの種類を 「Excel マクロ有効ブック (*.xlsm)」 に変更して保存
.xlsx のままだとマクロが保存されない。必ず .xlsm にすること。
シートを2つ用意する
このマクロには以下の2つのシートが必要。
1. 「一覧表」シート — データを入力するシート
| A | B | C | D | E | |
|---|---|---|---|---|---|
| 1 | 顧客名 | 品目 | 数量 | 単価 | 備考 |
| 2 | 山田商事 | Webサイト制作 | 1 | 300000 | 初回案件 |
| 3 | 鈴木工業 | システム保守(月額) | 12 | 50000 | 年間契約 |
- 1行目はヘッダー(データは2行目から)
- A列: 顧客名、B列: 品目、C列: 数量、D列: 単価、E列: 備考
2. 「テンプレート」シート — 見積書のひな形
| セル | 内容 | 書式設定(推奨) |
|---|---|---|
| B2 | (見積番号が入る) | 文字列 |
| B3 | (見積日が入る) | 日付(yyyy/mm/dd) |
| B4 | (有効期限が入る) | 日付(yyyy/mm/dd) |
| B6 | (宛先が入る) | 文字列 |
| B10 | (品目が入る) | 文字列 |
| C10 | (数量が入る) | 数値(#,##0) |
| D10 | (単価が入る) | 通貨(\\#,##0) |
| E10 | (金額が入る) | 通貨(\\#,##0) |
| E14 | (小計が入る) | 通貨(\\#,##0) |
| E15 | (消費税が入る) | 通貨(\\#,##0) |
| E16 | (合計が入る) | 通貨(\\#,##0) |
| B18 | (備考が入る) | 文字列 |
テンプレートシートには罫線やタイトル(「御見積書」など)を事前に設定しておく。セルの書式設定(通貨表示 \\#,##0、日付表示 yyyy/mm/dd)もテンプレート側で済ませておくと仕上がりがきれい。
テンプレートの印刷設定(用紙サイズ・余白・印刷範囲)は事前に設定しておくこと。設定方法は 【VBA】印刷設定を自動化する方法 を参照。
—
手順(コピペ → 実行まで約5分)
VBE(コードを書く画面)を開く
Alt + F11 キーを押すとVBE(Visual Basic Editor)が開く。
一般的にはAlt + F11で開けるが、企業のセキュリティ設定でVBAが無効化されている場合は、IT部門に確認すること。
標準モジュールを挿入する
- VBEのメニュー「挿入」→「標準モジュール」をクリック
- 右側に白い画面(コードウィンドウ)が表示される
コードを貼り付けて実行する
- 下の「コード(最小版)」をコピーして、コードウィンドウに貼り付ける
- Alt + F8 を押す(または VBE上で F5)
- 「CreateEstimate」を選択して「実行」
- 処理が完了すると、メッセージボックスが表示される
—
コード(最小版)– 1件の見積書をテンプレートから作成
まずはこれだけで動く。「一覧表」シートの2行目(1件目)のデータを「テンプレート」シートに転記して、見積書シートを1枚作成する。
Sub CreateEstimate()
Dim wsList As Worksheet
Dim wsTemplate As Worksheet
Dim wsNew As Worksheet
Dim customerName As String
Dim itemName As String
Dim quantity As Long
Dim unitPrice As Long
Dim amount As Long
Dim subtotal As Long
Dim tax As Long
Dim total As Long
Dim estNo As String
' --- シートを取得 ---
Set wsList = ThisWorkbook.Worksheets("一覧表")
Set wsTemplate = ThisWorkbook.Worksheets("テンプレート")
' --- 一覧表の2行目からデータを取得 ---
customerName = wsList.Cells(2, 1).Value ' A2: 顧客名
itemName = wsList.Cells(2, 2).Value ' B2: 品目
quantity = CLng(wsList.Cells(2, 3).Value) ' C2: 数量
unitPrice = CLng(wsList.Cells(2, 4).Value) ' D2: 単価
' --- 金額を計算 ---
amount = quantity * unitPrice
subtotal = amount
tax = Int(subtotal * 0.1) ' 消費税(10%)小計に対して計算
total = subtotal + tax
' --- 見積番号を生成 ---
estNo = "EST-001"
' --- テンプレートシートをコピー(末尾に追加) ---
wsTemplate.Copy After:=Sheets(Sheets.Count)
Set wsNew = ActiveSheet
wsNew.Name = estNo
' --- データを転記 ---
wsNew.Range("B2").Value = estNo ' 見積番号
wsNew.Range("B3").Value = Date ' 見積日(当日)
wsNew.Range("B4").Value = DateAdd("m", 1, Date) ' 有効期限(1ヶ月後)
wsNew.Range("B6").Value = customerName & " 御中" ' 宛先
wsNew.Range("B10").Value = itemName ' 品目
wsNew.Range("C10").Value = quantity ' 数量
wsNew.Range("D10").Value = unitPrice ' 単価
wsNew.Range("E10").Value = amount ' 金額
wsNew.Range("E14").Value = subtotal ' 小計
wsNew.Range("E15").Value = tax ' 消費税
wsNew.Range("E16").Value = total ' 合計
wsNew.Range("B18").Value = wsList.Cells(2, 5).Value ' 備考
MsgBox "見積書を作成しました。" & vbCrLf & _
"見積番号:" & estNo & vbCrLf & _
"顧客名:" & customerName, vbInformation
End Sub
コードの動作:
- 「一覧表」シートの2行目から顧客名・品目・数量・単価を取得
- 金額(数量×単価)、消費税(小計の10%)、合計を計算
- 「テンプレート」シートをコピーして新しいシートを作成
- 見積番号・日付・宛先・明細・金額を転記
- 完了メッセージを表示
ポイント: 消費税は Int(subtotal * 0.1) で小計に対して1回だけ計算する。明細ごとに計算すると端数のズレが起きることがある。
コード解説: まず wsList.Cells(2, 1).Value で一覧表シートの2行目1列目(A2セル)から顧客名を取得している。同じ要領でB2〜D2から品目・数量・単価を読み取る。次に wsTemplate.Copy After:=Sheets(Sheets.Count) でテンプレートシートをブック末尾にコピーし、コピーされた新しいシート(ActiveSheet)に対してデータを転記している。DateAdd("m", 1, Date) は現在日付の1ヶ月後を返す関数で、見積書の有効期限に使っている。
自分はこの最小版で「テンプレートにデータが自動で入る」のを見たとき、手入力に戻れないと思った。
テンプレートへのデータ転記の仕組みをもっと詳しく知りたい場合は 【VBA】一覧表からExcelテンプレートに差し込み印刷する方法 を参照。
—
コード(実務版)– 一覧表から複数の見積書を一括作成→PDF保存
業務で使うなら、一覧表の全行から見積書を一括で作成してPDF保存したい。連番の自動採番、PDF出力先フォルダの自動作成、エラースキップ付き。
PDF出力の詳しいパラメータについては 【VBA】ExcelファイルをPDFに一括変換する方法 で解説している。
出力フォルダ構成:
C:\見積書出力\
├── EST-001_山田商事_見積書.pdf
├── EST-002_鈴木工業_見積書.pdf
└── EST-003_田中建設_見積書.pdf
Sub CreateEstimateBatch()
Dim wsList As Worksheet
Dim wsTemplate As Worksheet
Dim wsNew As Worksheet
Dim fso As Object
Dim outputPath As String
Dim customerName As String
Dim itemName As String
Dim quantity As Long
Dim unitPrice As Long
Dim amount As Long
Dim subtotal As Long
Dim tax As Long
Dim total As Long
Dim estNo As String
Dim pdfName As String
Dim lastRow As Long
Dim row As Long
Dim seqNo As Long
Dim fileCount As Long
Dim errCount As Long
Dim taxRate As Double
' --- ★ ここを自分の出力先フォルダに書き換える ---
outputPath = "C:\見積書出力\"
' --- 消費税率(変更時はここを修正) ---
taxRate = 0.1
' フォルダパスの末尾に \ がなければ追加
If Right(outputPath, 1) <> "\" Then outputPath = outputPath & "\"
' 出力先フォルダがなければ作成
Set fso = CreateObject("Scripting.FileSystemObject")
If Not fso.FolderExists(outputPath) Then
fso.CreateFolder outputPath
End If
Set fso = Nothing
' --- シートを取得 ---
Set wsList = ThisWorkbook.Worksheets("一覧表")
Set wsTemplate = ThisWorkbook.Worksheets("テンプレート")
' --- データの最終行を取得 ---
lastRow = wsList.Cells(wsList.Rows.Count, 1).End(xlUp).row
If lastRow < 2 Then
MsgBox "一覧表にデータがありません。", vbExclamation
Exit Sub
End If
' 画面更新を停止(高速化)
Application.ScreenUpdating = False
Application.DisplayAlerts = False
fileCount = 0
errCount = 0
seqNo = 0
' --- 一覧表の各行を処理 ---
For row = 2 To lastRow
' 顧客名が空なら行をスキップ
If Trim(wsList.Cells(row, 1).Value) = "" Then GoTo NextRow
On Error GoTo ErrHandler
' --- データを取得 ---
customerName = wsList.Cells(row, 1).Value
itemName = wsList.Cells(row, 2).Value
quantity = CLng(wsList.Cells(row, 3).Value)
unitPrice = CLng(wsList.Cells(row, 4).Value)
' --- 金額を計算 ---
amount = quantity * unitPrice
subtotal = amount
tax = Int(subtotal * taxRate)
total = subtotal + tax
' --- 連番を採番 ---
seqNo = seqNo + 1
estNo = "EST-" & Format(seqNo, "000")
' --- テンプレートシートをコピー ---
wsTemplate.Copy After:=Sheets(Sheets.Count)
Set wsNew = ActiveSheet
wsNew.Name = estNo
' --- データを転記 ---
wsNew.Range("B2").Value = estNo
wsNew.Range("B3").Value = Date
wsNew.Range("B4").Value = DateAdd("m", 1, Date)
wsNew.Range("B6").Value = customerName & " 御中"
wsNew.Range("B10").Value = itemName
wsNew.Range("C10").Value = quantity
wsNew.Range("D10").Value = unitPrice
wsNew.Range("E10").Value = amount
wsNew.Range("E14").Value = subtotal
wsNew.Range("E15").Value = tax
wsNew.Range("E16").Value = total
wsNew.Range("B18").Value = wsList.Cells(row, 5).Value
' --- PDFとして保存 ---
pdfName = estNo & "_" & customerName & "_見積書.pdf"
wsNew.ExportAsFixedFormat _
Type:=xlTypePDF, _
Filename:=outputPath & pdfName, _
Quality:=xlQualityStandard, _
IncludeDocProperties:=False, _
IgnorePrintAreas:=False, _
OpenAfterPublish:=False
fileCount = fileCount + 1
On Error GoTo 0
NextRow:
Next row
' 画面更新を再開
Application.ScreenUpdating = True
Application.DisplayAlerts = True
MsgBox "完了" & vbCrLf & _
"作成:" & fileCount & " 件" & vbCrLf & _
"エラー:" & errCount & " 件" & vbCrLf & _
"出力先:" & outputPath, vbInformation
Exit Sub
ErrHandler:
errCount = errCount + 1
' コピーしたシートがあれば削除
If Not wsNew Is Nothing Then
Application.DisplayAlerts = False
wsNew.Delete
Application.DisplayAlerts = True
Set wsNew = Nothing
End If
' Application 設定を確実に復帰
Application.ScreenUpdating = True
Application.DisplayAlerts = True
On Error GoTo 0
Resume NextRow
End Sub
追加ポイント:
- 一覧表の全行を For ループで処理(空行はスキップ)
- 連番を
EST-001,EST-002, … で自動採番(Format(seqNo, "000")でゼロ埋め) - 有効期限を見積日の1ヶ月後に自動設定
- 各見積書をPDFとして出力先フォルダに保存
- 出力先フォルダがなければ FSO で自動作成
- エラーが出た行はスキップして次へ進む
- 消費税率を
taxRate変数で管理(税率変更時に1箇所だけ修正すればOK) - エラーハンドラで Application.ScreenUpdating / DisplayAlerts を確実に復帰
コード解説: For row = 2 To lastRow のループで一覧表の2行目から最終行まで1行ずつ処理している。最終行の取得には Cells(Rows.Count, 1).End(xlUp).Row を使っており、A列の最後のデータがある行番号を返す(詳しくは 最終行・最終列を取得する方法 を参照)。ExportAsFixedFormat はExcelシートをPDFファイルとして保存するメソッドで、IgnorePrintAreas:=False を指定することでテンプレートに設定した印刷範囲が反映される。エラーハンドラ ErrHandler ではコピー済みのシートを削除してからループの次の行に進むため、1件のエラーで全体が止まることがない。
作成した見積書PDFをメールに添付して送信したい場合は 【VBA】Excelファイルをメールに自動添付して送信する方法 を参照。
—
よくある落とし穴5選
自分が初めてVBAで見積書を自動作成したとき、消費税の計算を明細ごとに Int(金額 * 0.1) で処理していた。ところが端数の丸めが合計行と明細行でズレていて、取引先から「合計金額が1円違うんですが」と指摘された。原因は明細ごとに消費税を切り捨てるか、小計に対して消費税を計算するかの違い。以来、消費税は小計に対して1回だけ計算するようにしている。
| # | 症状 | 原因 | 対策 |
|---|---|---|---|
| 1 | 消費税が合計と明細で1円ズレる | 明細行ごとに Int(金額 * 税率) で切り捨てていて、小計に対する税額と不一致になっている |
消費税は小計に対して1回だけ計算する。tax = Int(subtotal * taxRate) |
| 2 | PDFが白紙で出力される | テンプレートシートに印刷範囲が設定されていない | テンプレートの印刷範囲を事前に設定しておく。印刷設定の自動化 も参考に |
| 3 | 見積番号が過去の案件と重複する | コードが毎回 EST-001 から採番するため、既存の番号と被る | 実務では採番開始番号を管理用セルに記録しておくか、既存の最大番号を取得して +1 する |
| 4 | 一覧表の空行でエラーが出る | 空行のセルを CLng() で変換しようとして型変換エラー | 顧客名が空の行はスキップする処理を入れる(実務版コードでは対応済み) |
| 5 | テンプレートのレイアウト変更後にコードが動かない | セル位置(B2, B6, E14 など)がハードコードされているため、行や列を追加するとズレる | テンプレートのレイアウトを変更したら、コード内のセル位置も修正する。またはセルに名前を付けて Range("見積番号") で参照する方法もある |
VBA 見積書 テンプレート 値が入らない場合の対処
テンプレートシートにデータが転記されない場合、まずシート名が正確に一致しているかを確認する。コード内の Worksheets("テンプレート") と実際のシート名が1文字でも違うと、実行時エラー9「インデックスが有効範囲にありません」が発生する。シート名の前後に空白が入っている場合も不一致になるので注意。また、転記先のセル位置(B2, B6, E10など)がテンプレートのレイアウトと合っているかも確認する。行や列を追加・削除した場合、コード内のセルアドレスも修正が必要。セルに名前を定義して Range("見積番号") のように参照する方式にすると、レイアウト変更に強くなる。
VBA 請求書 自動作成 印刷 ずれる場合の対処
PDFや印刷で見積書のレイアウトがずれる場合、テンプレートシートの印刷設定が原因であることが多い。まず「ページレイアウト」タブで印刷範囲が正しく設定されているか確認する。印刷範囲が未設定だとシート全体が対象になり、白紙ページが出力されたりレイアウトが崩れたりする。次に、用紙サイズ(A4)と余白の設定を確認する。テンプレートの列幅が広すぎて1ページに収まっていない場合は、「ページレイアウト」タブの「拡大縮小印刷」で「横: 1ページ」に設定すると改善する。ExportAsFixedFormat でPDF出力する際に IgnorePrintAreas:=False を指定していないと印刷範囲が無視されるので、この引数も必ず確認する。
一覧表のデータ型が原因で金額計算がおかしくなる場合
一覧表の数量や単価のセルが文字列として入力されていると、CLng() による型変換でエラーが発生したり、計算結果が0になったりする。セルの表示形式が「文字列」になっている場合は「数値」に変更し、値を再入力する。また、セルに全角数字(123)が入っていると CLng() が失敗するため、事前に半角に統一しておく必要がある。全角・半角の変換を自動化したい場合は 全角・半角を一括変換する方法 を参照。
—
FAQ
Q1: 納品書にも使えますか?
テンプレートシートの見出しを「御納品書」に変えて、番号のプレフィックスを DLV- にするだけで納品書にも使える。コード内の estNo = "EST-" を estNo = "DLV-" に変更し、テンプレートシート名を「テンプレート_納品書」などにすればよい。
Q2: 明細行が複数ある見積書を作りたい
この記事のコードは「1顧客=1品目」のシンプルな構成。明細行が複数ある場合は、一覧表を顧客ごとにグループ化して、明細行を For ループで B10〜B13 などに転記する。構成が複雑になるため、一覧表からテンプレートに差し込み印刷する方法 も参考にしてほしい。
Q3: 消費税率を変えたい
実務版コードの taxRate = 0.1 を変更するだけ。たとえば軽減税率8%なら taxRate = 0.08 に変える。品目によって税率が異なる場合は、一覧表に「税率」列を追加してそこから読み取る方式に変更する。
Q4: 作成した見積書をメールで送りたい
【VBA】Excelファイルをメールに自動添付して送信する方法 を参照。PDF保存後のファイルパスを .Attachments.Add に渡せば添付できる。一覧表にメールアドレス列を追加すれば、見積書作成→PDF保存→メール送信を一気に自動化できる。
Q5: 見積書をExcelファイル(.xlsx)として保存したい
PDF保存の代わりに、テンプレートをコピーして新しいブックとして保存する方法がある。wsTemplate.Copy(引数なし)で新しいブックが開くので、ActiveWorkbook.SaveAs Filename:=パス, FileFormat:=xlOpenXMLWorkbook で保存する。
—
まとめ
この記事で、一覧表のデータから見積書・納品書をテンプレートで自動作成できるようになった。月末に丸1日かけていた見積書作成が、一覧表にデータを入力してマクロを実行するだけで完了する。転記ミスも番号の重複もなくなるので、作業時間だけでなく精神的な負担も大幅に軽減できる。
- 最小版:一覧表の1件目 → テンプレートに転記して見積書シートを作成
- 実務版:一覧表の全件 → 連番採番+消費税計算+PDF一括保存
重要なのは、消費税は小計に対して1回だけ計算すること。明細ごとに切り捨てると端数がズレる。まず1件だけテスト作成してから本番実行するのがおすすめ。
関連記事
- 【VBA】請求書を自動作成する方法 — 見積書と同じ仕組みで請求書も自動作成できる
- 【VBA】一覧表からExcelテンプレートに差し込み印刷する方法 — テンプレートへのデータ転記の基本を学べる
- 【VBA】印刷設定を自動化する方法 — テンプレートの印刷レイアウトを自動で設定したい場合
次にやりたくなること
- 請求書を自動作成する方法: 見積書の次は請求書も自動化したい場合。同じテンプレート転記の仕組みで作れる
- Excelファイルをメールに自動添付して送信する方法: PDF見積書をメールに添付して送信したい場合。見積書作成からメール送信まで一気通貫で自動化できる
- テンプレートシートをコピーして月別・担当者別に量産する方法: テンプレートを大量にコピーしてシートを量産したい場合。月別や担当者別の帳票作成に応用できる
- ExcelファイルをPDFに一括変換する方法: PDF出力のパラメータ(品質・用紙サイズ・ページ範囲)を細かく制御したい場合
- 実行ログをシートに自動記録する方法: 見積書の作成履歴(いつ・誰宛に・何番で作成したか)を自動でログに残したい場合
—
もっとカスタマイズしたい場合
「複数明細行の見積書を作りたい」「見積書→納品書→請求書を連動させたい」「見積書作成と同時にメール送信もしたい」など、業務に合わせたカスタマイズが必要な場合は、ココナラで相談できます。
相談時に以下の情報があるとスムーズです:
- Excel のバージョン / OS
- テンプレートのレイアウト(スクリーンショット)
- 一覧表の列構成
- 見積番号の採番ルール(既存の番号体系がある場合)


コメント