はじめに
VBA100本ノック、85日目のテーマは「請求日から入金予定日を算出」です。ビジネスシーンにおいて、請求日を基に入金予定日を計算する作業は非常に一般的であり、このプロセスをVBAで自動化できれば、日々の業務効率を飛躍的に向上させることができます。請求日からの経過日数(例:月末締め翌月末払い、30日後払いなど)は、企業ごとに、あるいは取引先ごとに異なる場合も多く、手作業での計算や管理はミスを誘発しやすく、時間もかかります。本記事では、この入金予定日算出をVBAでどのように実装するか、具体的なコード例と解説を交えながら、実践的なスキルとして習得できる内容を目指します。
請求日から入金予定日を算出するロジック
入金予定日を算出する基本的な考え方は、請求日に対して一定の日数を加算することです。しかし、実際のビジネスにおいては、単に「〇日後」という単純な計算だけでなく、以下のような様々な条件が考慮されることがあります。
* **月末締め翌月末払い:** 例えば、1月15日の請求書は、1月末締めとなり、入金予定日は2月末日となります。
* **〇日後払い:** 例えば、請求日から30日後に入金、あるいは請求日から60日後に入金といったケースです。
* **特定曜日の入金:** 例えば、毎月第4金曜日に入金、といったケースもあります。
* **締め日と支払い日の関係:** 月末締めの場合、その月の末日を基準に支払い日を計算します。
これらの多様な条件に対応するため、VBAでは日付関数を駆使し、柔軟なロジックを組む必要があります。
VBAでの実装方法:サンプルコードと解説
ここでは、いくつかの典型的なパターンに基づいたVBAコード例を紹介します。
パターン1:請求日から単純に〇日後に入金予定日を算出する
このパターンは最もシンプルで、請求日から指定した日数(例:30日、60日)を加算するだけです。
Sub CalculatePaymentDate_Simple()
Dim invoiceDate As Date
Dim paymentDays As Integer
Dim paymentDate As Date
‘ 請求日を入力(例として直接指定)
invoiceDate = #2023/10/27# ‘ 例: 2023年10月27日
‘ 支払いまでの日数(例として直接指定)
paymentDays = 30 ‘ 例: 30日後
‘ 入金予定日を計算
paymentDate = invoiceDate + paymentDays
‘ 結果を表示
MsgBox “請求日: ” & Format(invoiceDate, “yyyy/mm/dd”) & vbCrLf & _
“支払い日数: ” & paymentDays & “日” & vbCrLf & _
“入金予定日: ” & Format(paymentDate, “yyyy/mm/dd”)
End Sub
**解説:**
* `Dim invoiceDate As Date`, `Dim paymentDays As Integer`, `Dim paymentDate As Date`: 変数を宣言しています。日付関連は`Date`型、日数は`Integer`型が適切です。
* `invoiceDate = #2023/10/27#`: 請求日を`Date`型で直接指定しています。実際には、セルから取得したり、ユーザーに入力させたりすることが多いでしょう。
* `paymentDays = 30`: 支払いまでの日数を指定しています。
* `paymentDate = invoiceDate + paymentDays`: VBAでは、`Date`型の変数に`Integer`型の数値を加算すると、その日数分だけ日付が進みます。これが日付計算の基本です。
* `MsgBox …`: 計算結果をメッセージボックスで表示しています。`Format`関数を使用することで、日付を任意の形式(ここでは「yyyy/mm/dd」)で表示できます。`vbCrLf`は改行コードです。
パターン2:月末締め翌月末払いを算出する
このパターンは、請求日の属する月の末日を基準に、翌月の末日を入金予定日とします。
Sub CalculatePaymentDate_EndOfMonth()
Dim invoiceDate As Date
Dim paymentDate As Date
‘ 請求日を入力(例として直接指定)
invoiceDate = #2023/10/15# ‘ 例: 2023年10月15日
‘ 請求日の属する月の末日を求める
Dim lastDayOfInvoiceMonth As Date
lastDayOfInvoiceMonth = DateSerial(Year(invoiceDate), Month(invoiceDate) + 1, 0) ‘ 次の月の0日目は当月の末日
‘ 入金予定日(翌月末)を計算
‘ 翌月の末日を求める。DateSerial(Year(lastDayOfInvoiceMonth), Month(lastDayOfInvoiceMonth) + 1, 0) でも良いが、
‘ 請求日から1ヶ月後と考える方が直感的かもしれない
paymentDate = DateSerial(Year(invoiceDate), Month(invoiceDate) + 1, 1) ‘ 翌月の1日
paymentDate = DateSerial(Year(paymentDate), Month(paymentDate) + 1, 0) ‘ その翌月の末日
‘ 結果を表示
MsgBox “請求日: ” & Format(invoiceDate, “yyyy/mm/dd”) & vbCrLf & _
“入金予定日 (月末締め翌月末払い): ” & Format(paymentDate, “yyyy/mm/dd”)
End Sub
**解説:**
* `lastDayOfInvoiceMonth = DateSerial(Year(invoiceDate), Month(invoiceDate) + 1, 0)`: `DateSerial`関数は、年、月、日を指定して日付を作成します。`Month(invoiceDate) + 1`で翌月を指定し、`Day`に`0`を指定すると、その月の前月の末日(つまり、請求日の属する月の末日)を取得できます。
* `paymentDate = DateSerial(Year(invoiceDate), Month(invoiceDate) + 1, 1)`: 請求日の属する月の翌月の1日を求めます。
* `paymentDate = DateSerial(Year(paymentDate), Month(paymentDate) + 1, 0)`: 上記で求めた翌月の1日から、さらに1ヶ月進み、その月の末日を計算します。これで「翌月末」が算出されます。
* 別の方法として、`DateAdd(“m”, 1, lastDayOfInvoiceMonth)`で翌月末を直接求めることもできますが、`DateSerial`の`0`日目のテクニックは覚えておくと便利です。
パターン3:請求日から〇日後、かつ月末が支払い日となる場合
例えば、「請求日から30日後」が支払い日だが、もしその日が月末よりも前なら、月末が入金日になる、といった条件を考慮します。
Sub CalculatePaymentDate_XDaysOrEndOfMonth()
Dim invoiceDate As Date
Dim paymentDays As Integer
Dim calculatedDate As Date
Dim finalPaymentDate As Date
‘ 請求日を入力(例として直接指定)
invoiceDate = #2023/10/10# ‘ 例: 2023年10月10日
‘ 支払いまでの日数(例として直接指定)
paymentDays = 30 ‘ 例: 30日後
‘ まず、請求日から〇日後を計算
calculatedDate = invoiceDate + paymentDays
‘ 請求日の属する月の末日を求める
Dim lastDayOfInvoiceMonth As Date
lastDayOfInvoiceMonth = DateSerial(Year(invoiceDate), Month(invoiceDate) + 1, 0)
‘ 最終的な入金予定日を決定
‘ calculatedDate が lastDayOfInvoiceMonth より後なら calculatedDate、
‘ そうでなければ lastDayOfInvoiceMonth を採用する(このロジックは少し変。通常は「月末よりも前なら月末」)
‘ ここでは「請求日から30日後」と「請求日の月末」を比較し、後日を採用する、という解釈で実装してみます。
‘ より一般的なのは「請求日から30日後」を計算し、もしそれが月末より前なら月末にする、というケースです。
‘ その場合は、If calculatedDate < lastDayOfInvoiceMonth Then finalPaymentDate = lastDayOfInvoiceMonth Else finalPaymentDate = calculatedDate End If となります。
' ここでは「請求日から30日後」と「請求日の属する月の末日」の、どちらか遅い方を入金予定日とする、というロジックで実装します。
If calculatedDate > lastDayOfInvoiceMonth Then
finalPaymentDate = calculatedDate
Else
finalPaymentDate = lastDayOfInvoiceMonth
End If
‘ 結果を表示
MsgBox “請求日: ” & Format(invoiceDate, “yyyy/mm/dd”) & vbCrLf & _
“支払い日数: ” & paymentDays & “日” & vbCrLf & _
“計算された日付: ” & Format(calculatedDate, “yyyy/mm/dd”) & vbCrLf & _
“請求月の末日: ” & Format(lastDayOfInvoiceMonth, “yyyy/mm/dd”) & vbCrLf & _
“最終入金予定日: ” & Format(finalPaymentDate, “yyyy/mm/dd”)
End Sub
**解説:**
* このパターンは、ビジネスロジックの解釈によって実装方法が変わる可能性があります。上記のコードは「請求日から〇日後」と「請求日の属する月の末日」を比較し、遅い方を入金予定日とする例です。
* より一般的な「請求日から〇日後」を計算し、それが月末よりも前であれば月末を入金予定日とする、というロジックにする場合は、`If calculatedDate < lastDayOfInvoiceMonth Then finalPaymentDate = lastDayOfInvoiceMonth Else finalPaymentDate = calculatedDate End If` のように条件分岐させます。
実務での応用と注意点
1. データの取得元
実際の業務では、請求日はExcelの特定のセルに入力されているか、データベースから取得することがほとんどです。上記サンプルコードの`invoiceDate = #2023/10/27#` の部分は、以下のように変更してセルから取得します。
‘ セルA1から請求日を取得する場合
invoiceDate = ThisWorkbook.Sheets(“Sheet1”).Range(“A1”).Value
2. 支払い条件の管理
支払い条件(〇日後払い、月末締め翌月末払い、取引先ごとの特殊条件など)は、固定値としてコードに埋め込むのではなく、別シートや別テーブルで管理することを強く推奨します。これにより、条件変更があった場合でもコードの修正が不要になり、メンテナンス性が向上します。
例えば、以下のような管理シートを作成します。
| 取引先ID | 支払い条件 | 支払日数 |
| :——- | :——- | :——- |
| 1001 | 30日後 | 30 |
| 1002 | 月末締め翌月末 | 0 |
| 1003 | 60日後 | 60 |
VBAでは、このシートから取引先IDに対応する支払い条件を読み込み、それに応じた計算ロジックを実行します。
3. エラーハンドリング
請求日セルが空欄だったり、日付として認識できない値が入っていたりする場合があります。このような場合にエラーが発生しないように、`On Error Resume Next` や `If IsDate()` などのエラーハンドリングを適切に実装することが重要です。
‘ セルA1から請求日を取得し、日付として有効かチェック
If IsDate(ThisWorkbook.Sheets(“Sheet1”).Range(“A1”).Value) Then
invoiceDate = ThisWorkbook.Sheets(“Sheet1”).Range(“A1”).Value
‘ 以降、計算処理
Else
MsgBox “請求日の形式が正しくありません。日付を入力してください。”, vbExclamation
Exit Sub ‘ 処理を中断
End If
4. 閏年・うるう年への対応
VBAの日付関数は、閏年を自動的に考慮してくれるため、通常は気にする必要はありません。ただし、特殊な計算ロジックを自分で組む場合は注意が必要です。
5. 処理の実行方法
* **ボタンクリック:** シート上にボタンを配置し、クリックイベントでマクロを実行する。
* **特定のセル変更時:** `Worksheet_Change` イベントを利用し、請求日セルが変更されたら自動的に入金予定日を計算して別セルに表示する。
* **定時実行:** `Application.OnTime` を使用して、特定の時間にマクロを実行する。
どの方法が最適かは、業務フローによって異なります。
まとめ
本記事では、「VBA100本ノック85日目:請求日から入金予定日を算出」をテーマに、基本的な日付計算から、月末締め翌月末払い、複合的な条件分岐まで、VBAでの実装方法を解説しました。
* 日付計算の基本は `Date` 型変数と数値の加算・減算。
* `DateSerial` 関数や `DateAdd` 関数を駆使することで、柔軟な日付計算が可能になる。
* 月末の判定や翌月末の算出には、`DateSerial(Year(date), Month(date) + 1, 0)` のテクニックが有効。
* 実務では、データの取得元、支払い条件の管理方法、エラーハンドリングが極めて重要。
これらの知識とサンプルコードを参考に、ぜひご自身の業務に合わせた入金予定日算出VBAを作成してみてください。日々のルーチンワークを自動化し、より生産性の高い業務遂行を目指しましょう。VBA100本ノックは続きます!
