和風スパゲティのレシピ

日本語でコーディングするExcelVBA

VBA問題#2「注文書をデータ取込」完成版解答

ExcelVBA練習問題シリーズ#2「注文書をデータ取込」の、
マクロ①②+挑戦ポイントにすべて対応した完全解答版です。

取込帳票
取込先データ

もちろんこれが正解という訳ではなく、いろいろなやり方あると思いますが、
ひとつの解答としてご参考ください。


◇ 出題ページはこちら
www.limecode.jp

◇ 解答ページはこちら
VBA問題#2「注文書をデータ取込」マクロ①解答
VBA問題#2「注文書をデータ取込」マクロ②解答
VBA問題#2「注文書をデータ取込」完成版解答(挑戦ポイント制覇)【本ページ】
 

ソースコード

モジュール全体像

標準モジュール:Df_シートレイアウト

Option Explicit

' 販売データ
Public Const Adrs販売データ_年度 = "F2"
Public Const R1st販売データ = 5
Public Const C1st販売データ = 2
Public Enum CNo販売データ
    No = C1st販売データ
    購入者
    月
    日
    品物
    価格
    個数
    売上
    取込日
End Enum
Public Const CLast販売データ = CNo販売データ.取込日

' 注文書
Public Const Adrs注文書_購入者 = "C5"
Public Const Adrs注文書_注文日 = "C7"
Public Const Adrs注文書_合計税別 = "F22"
Public Const Adrs注文書_消費税 = "F23"
Public Const Adrs注文書_合計税込 = "F24"
Public Const R1st注文書 = 12
Public Const RLast注文書 = 21
Public Const C1st注文書 = 2
Public Enum CNo注文書
    No = C1st注文書
    品物
    価格
    個数
    金額
End Enum
Public Const CLast注文書 = CNo注文書.金額

' 実行シート
Public Const Adrs実行シート_ファイルパス = "C4"
Public Const Adrs実行シート_フォルダパス = "C9"
Public Const R1st取込ログ = 12
Public Const C1st取込ログ = 2
Public Enum CNo取込ログ
    No = C1st取込ログ
    取込ファイル名
    結果
End Enum
Public Const CLast取込ログ = CNo取込ログ.結果


Function Is注文書シート(判定シート As Worksheet) As Boolean
    Is注文書シート = 判定シート.Range("B2") = "注  文  書" _
                 And 判定シート.Range("D24") = "合計(税込)"
End Function

標準モジュール:Pr0_注文書取込_共通コード

Option Explicit

' 注文書 → 販売データ
Sub 指定の注文書シートを販売データに取り込む(ws注文書 As Worksheet)

    ' 出力第1行(最終行+1)と出力No(最大値+1)を取得
    Dim R_出力 As Long: R_出力 = Get最終行(WS販売データ) + 1
    Dim 出力No As Long: 出力No = WorksheetFunction.Max(WS販売データ.Columns(CNo販売データ.No)) + 1
    
    ' 注文書の表部分をループ
    Dim R_取込 As Long
    For R_取込 = R1st注文書 To RLast注文書
    
        ' 金額が0でない行を取込
        If ws注文書.Cells(R_取込, CNo注文書.金額) <> 0 Then

            WS販売データ.Cells(R_出力, CNo販売データ.No) = 出力No
            WS販売データ.Cells(R_出力, CNo販売データ.購入者) = ws注文書.Range(Adrs注文書_購入者)
            WS販売データ.Cells(R_出力, CNo販売データ.) = Month(ws注文書.Range(Adrs注文書_注文日))
            WS販売データ.Cells(R_出力, CNo販売データ.) = Day(ws注文書.Range(Adrs注文書_注文日))
            WS販売データ.Cells(R_出力, CNo販売データ.品物) = ws注文書.Cells(R_取込, CNo注文書.品物)
            WS販売データ.Cells(R_出力, CNo販売データ.価格) = ws注文書.Cells(R_取込, CNo注文書.価格)
            WS販売データ.Cells(R_出力, CNo販売データ.個数) = ws注文書.Cells(R_取込, CNo注文書.個数)
            WS販売データ.Cells(R_出力, CNo販売データ.売上) = ws注文書.Cells(R_取込, CNo注文書.金額)
            WS販売データ.Cells(R_出力, CNo販売データ.取込日) = Date
            
            ' 出力行とNoを更新
            R_出力 = R_出力 + 1
            出力No = 出力No + 1
            
        End If
    
    Next ' 注文書の表部分をループ


End Sub

' 取込済判定(同日同購入者で判定)
Function Is指定注文書が販売データに取込済(ws注文書 As Worksheet) As Boolean
    
    ' そもそも年度が異なればExit
    If WS販売データ.Range(Adrs販売データ_年度) <> Get年度(ws注文書.Range(Adrs注文書_注文日)) Then Exit Function
    
    ' 判定キーの取得
    Dim key月 As Long: key月 = Month(ws注文書.Range(Adrs注文書_注文日))
    Dim key日 As Long: key日 = Day(ws注文書.Range(Adrs注文書_注文日))
    Dim key購入者 As String: key購入者 = ws注文書.Range(Adrs注文書_購入者)
    
    ' 全キーが一致するデータがあるか判定
    Dim R As Long
    For R = R1st販売データ To Get最終行(WS販売データ)
    
        If WS販売データ.Cells(R, CNo販売データ.) = key月 _
        And WS販売データ.Cells(R, CNo販売データ.) = key日 _
        And WS販売データ.Cells(R, CNo販売データ.購入者) = key購入者 Then
            Is指定注文書が販売データに取込済 = True
            Exit Function
        End If
    
    Next
    
End Function

標準モジュール:Pr1_注文書取込_ファイル指定

Option Explicit

' マクロ① 指定パスの注文書を取込
Sub 指定した注文書ファイルを販売データに取り込む()

    ' 取込ファイルの存在・ファイル形式チェック
    Dim path取込ファイル As String: path取込ファイル = WS実行シート.Range(Adrs実行シート_ファイルパス)
    Dim 取込ファイル名 As String: 取込ファイル名 = Dir(path取込ファイル)
    
    If 取込ファイル名 = "" Then MsgBox "指定したファイルが存在しません。": Exit Sub
    If Right(取込ファイル名, 5) <> ".xlsx" Then MsgBox "指定ファイルがxlsxファイルではありません。": Exit Sub
    
    ' 対象ブックを開く
    Dim path保存フォルダ As String: path保存フォルダ = Replace(path取込ファイル, "\" & 取込ファイル名, "")
    Dim wb取込ファイル As Workbook
    Set wb取込ファイル = ブックを開いていなければ開く(path保存フォルダ, 取込ファイル名)
    
    ' シートの存在チェック
    If Isシートが存在する("注文書", wb取込ファイル) = False Then MsgBox "注文書シートがないファイルです。": Exit Sub
    Dim ws注文書 As Worksheet: Set ws注文書 = wb取込ファイル.Worksheets("注文書")
    
    ' シートのレイアウトチェック
    If Is注文書シート(ws注文書) = False Then MsgBox "注文書シートのレイアウトが異なります。": Exit Sub

    ' 対象年度が異なれば取込を停止
    If WS販売データ.Range(Adrs販売データ_年度) <> Get年度(ws注文書.Range(Adrs注文書_注文日)) Then MsgBox "注文書の年度が異なります。": Exit Sub
        
    ' 取込済判定
    If Is指定注文書が販売データに取込済(ws注文書) Then MsgBox "同日同購入者のデータが既に存在します。": Exit Sub

    Dim R_第1出力行 As Long: R_第1出力行 = Get最終行(WS販売データ) + 1
        
    ' ■ 取込メインプロシージャを実行
    Call 指定の注文書シートを販売データに取り込む(ws注文書)
    
    Dim R_最終出力行 As Long: R_最終出力行 = Get最終行(WS販売データ)
            
    WS販売データ.Activate
    WS販売データ.Range(WS販売データ.Rows(R_第1出力行) _
                     , WS販売データ.Rows(R_最終出力行)).Select
    MsgBox "データの取込を完了しました。"
    
End Sub

標準モジュール:Pr2_注文書取込_フォルダ一括

Option Explicit

' マクロ② 指定フォルダ内の全注文書を取込
Sub 指定フォルダ内にあるすべての注文書ファイルを販売データに取り込む()

    ' 取込ログをクリア
    WS実行シート.Range(WS実行シート.Rows(R1st取込ログ), WS実行シート.Rows(Get最終行(WS実行シート))).Value = ""

    ' 取込フォルダの存在チェック
    Dim Path取込フォルダ As String: Path取込フォルダ = WS実行シート.Range(Adrs実行シート_フォルダパス)
    If Dir(Path取込フォルダ, vbDirectory) = "" Then MsgBox "指定したフォルダが存在しません。": Exit Sub
    
    ' 処理後の移動先フォルダを作成
    Dim Path完了フォルダ As String: Path完了フォルダ = Path取込フォルダ & "\" & Format(Date, "yyyymmdd") & "取込済"
    Dim Path除外フォルダ As String: Path除外フォルダ = Path取込フォルダ & "\除外ファイル"
    If Dir(Path完了フォルダ, vbDirectory) = "" Then MkDir Path完了フォルダ
    If Dir(Path除外フォルダ, vbDirectory) = "" Then MkDir Path除外フォルダ
    
    ' ファイルの存在チェック
    Dim dirファイル名 As String: dirファイル名 = Dir(Path取込フォルダ & "\*.xlsx")
    If dirファイル名 = "" Then MsgBox "指定フォルダ内にxlsxファイルがひとつもありません。": Exit Sub
    
    ' 第1出力列を記憶
    Dim R_第1出力行 As Long: R_第1出力行 = Get最終行(WS販売データ) + 1
    
    ' フォルダ内のすべてのxlsxファイルを取得
    Dim 取込ファイルNo As Long: 取込ファイルNo = 1
    Dim R_ログ As Long: R_ログ = R1st取込ログ
    Do While dirファイル名 <> ""
    
        ' ファイル名とNoをログに記録
        WS実行シート.Cells(R_ログ, CNo取込ログ.No) = 取込ファイルNo
        WS実行シート.Cells(R_ログ, CNo取込ログ.取込ファイル名) = dirファイル名
        
        ' 注文書シートの取得
        On Error Resume Next
            Dim wb取込ファイル As Workbook
            Set wb取込ファイル = ブックを開いていなければ開く(Path取込フォルダ, dirファイル名)
            Dim ws注文書 As Worksheet: Set ws注文書 = wb取込ファイル.Worksheets("注文書")
        On Error GoTo 0
        
        ' 注文書シートがない
        If ws注文書 Is Nothing Then
            WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "注文書シートなし"
        
        ' 注文書のレイアウトが不一致
        ElseIf Is注文書シート(ws注文書) = False Then
            WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "シートレイアウト不一致"
        
        ' 対象年度でない
        ElseIf WS販売データ.Range(Adrs販売データ_年度) <> Get年度(ws注文書.Range(Adrs注文書_注文日)) Then
            WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "データ年度不一致"
            
        ' 取込済
        ElseIf Is指定注文書が販売データに取込済(ws注文書) Then
            WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "取込済の注文書"
        
        ' ■ 取込を実行
        Else
            Call 指定の注文書シートを販売データに取り込む(ws注文書)
            WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "完了"
        End If
        
        ' ファイルを開いていたら閉じる
        If Not wb取込ファイル Is Nothing Then wb取込ファイル.Close False
    
        ' 結果が「完了」かどうかで判定
        If WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "完了" Then
            Name Path取込フォルダ & "\" & dirファイル名 As Path完了フォルダ & "\" & dirファイル名
        Else
            Name Path取込フォルダ & "\" & dirファイル名 As Path除外フォルダ & "\" & dirファイル名
        End If
    
        ' 次のファイルへ
        取込ファイルNo = 取込ファイルNo + 1
        R_ログ = R_ログ + 1
        dirファイル名 = Dir()
    
    Loop ' フォルダ内のすべてのxlsxファイルを取得
    
    Dim R_最終出力行 As Long: R_最終出力行 = Get最終行(WS販売データ)
            
    WS販売データ.Activate
    WS販売データ.Range(WS販売データ.Rows(R_第1出力行) _
                     , WS販売データ.Rows(R_最終出力行)).Select
    MsgBox "データの取込を完了しました。"

End Sub

' フォルダのダイアログ選択
Sub フォルダを選択する()
    
    WS実行シート.Range("C9") = GetPathダイアログボックスでフォルダを選択する(ThisWorkbook.Path)

End Sub

Function GetPathダイアログボックスでフォルダを選択する(Optional Path初期表示フォルダ As String = "") As String
    With Application.FileDialog(msoFileDialogFolderPicker)

        If Path初期表示フォルダ <> "" Then .InitialFileName = Path初期表示フォルダ

        If .Show Then: GetPathダイアログボックスでフォルダを選択する = .SelectedItems(1)
    
    End With
End Function

標準モジュール:Ut_汎用関数

Option Explicit

' 最終行の取得
Function Get最終行(指定シート As Worksheet, Optional 列番号 As Long = -1) As Long
    With 指定シート
    
        ' 列番号を省略時はシートの最終行
        If 列番号 = -1 Then
            Get最終行 = .UsedRange.Rows.Count + .UsedRange.Row - 1
    
        ' 列番号を指定時は列の最終行
        Else
            Get最終行 = .Cells(.Rows.Count, 列番号).End(xlUp).Row
        End If
    
    End With
End Function

' ブックを開いていなければ開く
Function ブックを開いていなければ開く(フォルダパス As String, ブック名 As String) As Workbook

    If Isブックを開いている(ブック名) Then
        Set ブックを開いていなければ開く = Workbooks(ブック名)
    Else
        On Error Resume Next
        Set ブックを開いていなければ開く = Workbooks.Open(フォルダパス & "\" & ブック名)
        On Error GoTo 0
    End If
    
End Function

' ブックのOpenチェック
Function Isブックを開いている(判定ブック名 As String) As Boolean

    ' 開いているすべてのブックを走査
    Dim wb As Workbook
    For Each wb In Workbooks
    
        ' ブック名が一致したらTrueを返してExit
        If wb.Name = 判定ブック名 Then
            Isブックを開いている = True
            Exit Function
        End If
        
    Next
    
End Function

' シートの存在チェック
Function Isシートが存在する(判定シート名 As String, 指定ブック As Workbook) As Boolean

    ' ブック内の全シートを走査
    Dim ws As Worksheet
    For Each ws In 指定ブック.Worksheets

        ' シート名が一致したらTrueを返してExit
        If ws.Name = 判定シート名 Then
            Isシートが存在する = True
            Exit Function
        End If

    Next

End Function

' 年度の取得
Function Get年度(ByVal 日付 As Date) As Long
    If Month(日付) >= 4 Then
        Get年度 = Year(日付)
    Else
        Get年度 = Year(日付) - 1
    End If
End Function

解説

処理の基本部分についての解説は、
マクロ①②の解答で詳しく行っていますのでそちらをご参考ください。
VBA問題#2「注文書をデータ取込」解答(マクロ①)
VBA問題#2「注文書をデータ取込」解答(マクロ②)


本記事では「挑戦ポイント」への対応内容を解説していきます。


コードを読む際は、上記マクロ①②の解答ファイルと見比べることで、
コードをどのように改良したかがより分かりやすくなると思います。

よろしければ横に並べてご覧ください。

レイアウト変更への対応を考慮した設計

【挑戦ポイント】
販売データの列の変更や、領収書のレイアウトの変更に対応できるよう設計してみてください。


こちらの課題、いわゆる「メンテナンス性の向上」については、
シートレイアウトをEnum・定数で定義しひとつのモジュールにまとめました。

軽微な変更(行列の挿入削除程度)であれば、
「Df_シートレイアウト」モジュールを変更するだけでマクロを改修できます。


簡単に解説しますと、Enum・定数を使用したことで、

WS販売データ.Cells(R_出力, 9) = ws注文書.Cells(R_取込, 6)

' ⇩ Enumと定数を使って書き替え

WS販売データ.Cells(R_出力, CNo販売データ.売上) = ws注文書.Cells(R_取込, CNo注文書.金額)

こんな風にコードが書き換わっています。


まずはコードが読めるようになっているというのが大きな利点ですが、
さらに強力なメリットとして、列の追加削除対応を瞬殺できるようになります。


例えば「購入者」列の右に「住所」列を追加するとしましょう。


Enumなしの場合は、Cells中身の「9」を「10」に書き換える作業を、
すべてコードから探して行う必要があります。

しかも注文書の方に出てくる数字を増やしてはいけませんので、
機械的に書き換えていくわけにもいかず、すべてのCellsをよく見なければいけません。

この大変さを味わったことがある人は多いはず。


しかしEnumを用いている場合は、
Enumの設定箇所を↓のように書き換えるだけで改修が完了してしまいます。

Public Const C1st販売データ = 2
Public Enum CNo販売データ
    No = C1st販売データ ' ここが2
    購入者   ' 以下Enumの自動連番機能で3,4,…と進む
    住所      ' ← これをEnumに追加。4となる ' ← ここから下は5,6,…と自動で+1されるので以下対応は不要!
    日
    品物
    価格
    個数
    売上      ' ← 9が10にしっかり変わっている!
    取込日
End Enum

素晴らしい機能ですよね!

列番号をいちいち打ち換える地獄のような作業が、
列名をひとつ書くだけで済むようになっています。


メンテナンス性を考えた時、これほど簡単で強力な機能はなかなかありませんので、
まだ使っていなかった方は是非一度使ってみて下さい。


Enumについては詳しく書いた記事がありますので、
興味がる方は是非ご覧下さい。
www.limecode.jp


またEnumの勉強会のYoutube配信アーカイブもありますので、
こちらもあわせてご活用いただければと思います。

Subプロシージャの分割

【挑戦ポイント】
マクロ1とマクロ2で同じコードを使えるように「Subプロシージャ」を分割してみてください。


こちらは「注文書1ファイル → 販売データ」のメイン処理部をプロシージャにしました。

マクロ1とマクロ2を1つのプロシージャで実装できているのも良さですが、
加えて両マクロともメインコードが簡潔になっているのも大きいですね。

特にマクロ2は「すべてのファイルを判定→開いて→処理→閉じる」というコードなのですが、
処理がCall1行になることでフォルダ走査のDoループ文が見渡しやすくなっています。


こういった長大なループを持つコードにおいては、
プロシージャ分割のメリット「処理に見出しをつけて1行にする」が活きてきます。

プロシージャ分割のメリットは「部品の共通化」だけではありませんので、
この使い方も意識していって下さい。


あとは全体的な話ですが、分割したプロシージャを、
モジュール全体像
こんな風に処理ごとにモジュール分割しているのも地味ですが重要なポイントです。

モジュールは名称によって自動で並び変わってしまいますので、
頭文字+数字を付けて並びをコントロールしましょう。

汎用関数の作成(年度版のDateSirial ほか)

【挑戦ポイント】
Get年度(日付 As Date) を「Functionプロシージャ」で作成してみてください。


こちらはまずその関数を作成しました。

' 年度の取得
Function Get年度(ByVal 日付 As Date) As Long
    If Month(日付) >= 4 Then
        Get年度 = Year(日付)
    Else
        Get年度 = Year(日付) - 1
    End If
End Function

 
こんな単純な関数でも、メインコードをこれだけスッキリかけるようになります。

Dim 注文書年度 As Long: 注文書年度 = Year(ws注文書.Range("C7"))
If Month(ws注文書.Range("C7")) <= 3 Then 注文書年度 = 注文書年度 - 1
If WS販売データ.Range("F2") = 注文書年度 Then

' ⇩ 関数を使って書き換え

If WS販売データ.Range("F2") <> Get年度(ws注文書.Range("C7")) Then

 
Functionと聞くと最初は難しそうに感じるかもしれませんが、
こういった単純な処理を切り出すだけなら案外簡単に作ることができます。

それでいて効果は抜群ですから、マクロづくりに慣れてきたら、
自作の汎用関数(ライブラリ)作りにぜひ挑戦してみましょう。


今回は汎用関数の例として、年度を取得する指定のDateSerialのほかに、
「Get最終行」「Isシートが存在する」「Isブックを開いている」
「ブックを開いていなければ開く」
も作成してみました。


「Get最終行」はおなじみのEndプロパティによる最終行取得ですが、
頻出なだけに、これも関数にしておくとサクサクコードが書けるようになります。


他3つの関数は、簡単だけど分岐・ループが必要な処理たちです。

この辺の処理は簡単なんですが意外とメインコードの行数を食ってしまうので、
汎用関数にすることでメインコードを相当スッキリさせることができます。

◇ 汎用関数未使用のマクロ①解答

On Error Resume Next

    ' ファイルを開いていなければ開く
    Dim wb取込ファイル As Workbook
    Set wb取込ファイル = Workbooks(取込ファイル名) ' ← 開いていなければエラーでスキップ
    
    If wb取込ファイル Is Nothing Then ' ↑がスキップされていればファイルを開く
        Set wb取込ファイル = Workbooks.Open(path取込ファイル)
    End If
    If wb取込ファイル Is Nothing Then MsgBox "何らかのエラーでファイルが開けませんでした。": Exit Sub

    ' シートの存在チェック
    Dim ws注文書 As Worksheet: Set ws注文書 = wb取込ファイル.Worksheets("注文書")
    If ws注文書 Is Nothing Then MsgBox "注文書シートがないファイルです。": Exit Sub
    
On Error GoTo 0

 
◇ 汎用関数を使用した今回のマクロ①解答

' 対象ブックを開く
Dim path保存フォルダ As String: path保存フォルダ = Replace(path取込ファイル, "\" & 取込ファイル名, "")
Dim wb取込ファイル As Workbook
Set wb取込ファイル = ブックを開いていなければ開く(path保存フォルダ, 取込ファイル名)

' シートの存在チェック
If Isシートが存在する("注文書", wb取込ファイル) = False Then MsgBox "注文書シートがないファイルです。": Exit Sub
Dim ws注文書 As Worksheet: Set ws注文書 = wb取込ファイル.Worksheets("注文書")

 
全体が見渡しやすくなり、各行もかなり読みやすくなっていますね。


このようによく書くコードを汎用関数にしておくと、
メインコードを劇的に書きやすく&読みやすくすることができます。

単純な処理をFunctionにするだけなら思ったよりも簡単ですので、
是非とも挑戦してみてください。

詳しくはこちらの記事をどうぞ。
www.limecode.jp

注文書ファイルのチェック

【挑戦ポイント】
注文書ファイルでないものを取り込まないよう実行前にチェックしてみてください。
同日同購入者の注文書はないものとしますので、それをもって「同じ注文書を2度取り込まない」チェックを追加してください。
これらのチェックを行い、除外したファイルもログに記録してください。

 
こちらはそれぞれの判定をFunction
「Is注文書シート」「Is指定注文書が販売データに取込済」

を作って対応しました。

Function Is注文書シート(判定シート As Worksheet) As Boolean
    Is注文書シート = 判定シート.Range("B2") = "注  文  書" _
                 And 判定シート.Range("D24") = "合計(税込)"
End Function

Function Is指定注文書が販売データに取込済(ws注文書 As Worksheet) As Boolean
    
    ' そもそも年度が異なればExit
    If WS販売データ.Range(Adrs販売データ_年度) <> Get年度(ws注文書.Range(Adrs注文書_注文日)) Then Exit Function
    
    ' 判定キーの取得
    Dim key月 As Long: key月 = Month(ws注文書.Range(Adrs注文書_注文日))
    Dim key日 As Long: key日 = Day(ws注文書.Range(Adrs注文書_注文日))
    Dim key購入者 As String: key購入者 = ws注文書.Range(Adrs注文書_購入者)
    
    ' 全キーが一致するデータがあるか判定
    Dim R As Long
    For R = R1st販売データ To Get最終行(WS販売データ)
    
        If WS販売データ.Cells(R, CNo販売データ.) = key月 _
        And WS販売データ.Cells(R, CNo販売データ.) = key日 _
        And WS販売データ.Cells(R, CNo販売データ.購入者) = key購入者 Then
            Is指定注文書が販売データに取込済 = True
            Exit Function
        End If
    
    Next
    
End Function

 
こういった判定は何度も出てくるため関数化しておくと便利ですし、
なによりメインコードが

' 注文書のレイアウトが不一致
ElseIf Is注文書シート(ws注文書) = False Then
    WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "シートレイアウト不一致"

' 取込済
ElseIf Is指定注文書が販売データに取込済(ws注文書) Then
    WS実行シート.Cells(R_ログ, CNo取込ログ.結果) = "取込済の注文書"

これだけ簡潔に読みやすくなっているのがポイントです。

Boolean型を返す判定関数を「Is○○」という名称にしておくと、
「If Is○○ Then」と文章っぽく読めるようになっていいですね。


前述の通り、Sub/Function分割の真の目的は
「処理に見出しをつけて1行に要約する」ことです。


是非とも活用し、メインコードをスッキリ読みやすいコードにしてください。



以上で挑戦ポイントを網羅した完成版の解説を終わります。

マクロ①②の解答コードと見比べると、
全く同じ処理でも全然違う書き方になっているのがわかります。


ある程度処理が書けるようになったら、
メンテナンス性や可読性を意識したコードに挑戦してみましょう。

マクロの改修が楽になったり、バグの発生率を落とすことができます。


コードの書き方にはいろいろな方法がありますので、
いろいろなコードを眺めて参考にしてみてください。