Contents
完成イメージ(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回だけ計算する。明細ごとに計算すると端数のズレが起きることがある。
自分はこの最小版で「テンプレートにデータが自動で入る」のを見たとき、手入力に戻れないと思った。
テンプレートへのデータ転記の仕組みをもっと詳しく知りたい場合は 【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 を確実に復帰
作成した見積書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("見積番号") で参照する方法もある |
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件目 → テンプレートに転記して見積書シートを作成
- 実務版:一覧表の全件 → 連番採番+消費税計算+PDF一括保存
重要なのは、消費税は小計に対して1回だけ計算すること。明細ごとに切り捨てると端数がズレる。まず1件だけテスト作成してから本番実行するのがおすすめ。
関連記事
- 【VBA】請求書を自動作成する方法 — 見積書と同じ仕組みで請求書も自動作成できる
- 【VBA】一覧表からExcelテンプレートに差し込み印刷する方法 — テンプレートへのデータ転記の基本を学べる
- 【VBA】印刷設定を自動化する方法 — テンプレートの印刷レイアウトを自動で設定したい場合
次にやりたくなること
- 【VBA】請求書を自動作成する方法 — 見積書の次は請求書も自動化したい場合はこちら
- 【VBA】Excelファイルをメールに自動添付して送信する方法 — PDF見積書をメールに添付して送信したい場合はこちら
もっとカスタマイズしたい場合
「複数明細行の見積書を作りたい」「見積書→納品書→請求書を連動させたい」「見積書作成と同時にメール送信もしたい」など、業務に合わせたカスタマイズが必要な場合は、ココナラで相談できます。
相談時に以下の情報があるとスムーズです:
- Excel のバージョン / OS
- テンプレートのレイアウト(スクリーンショット)
- 一覧表の列構成
- 見積番号の採番ルール(既存の番号体系がある場合)


コメント