【Project VBA極限知見】進捗率に魂を縛れ!Assignmentオブジェクトで実現する「真のコスト按分」自動化アーキテクチャ
こんにちは、チーフアーキテクトの私だ。
Project VBAの世界において、リソース管理ほど「お茶を濁したコード」が横行する領域はない。
ネットを検索すれば「 `Task.Cost` を引っ張ってきて合計すればいい」といった、実務の現場を知らない素人の玩具のようなコードが溢れかえっている。だが、考えてみてほしい。プロジェクト管理の本質とは何だ? 「進捗(実績)に見合ったコストの正確な把握」 に他ならない。
スケジュールが50%消化されていようが、コストが全額前払いされているわけではない。リソースの稼働率、そしてタスクの「実進捗率( `% Complete` または `% Work Complete` )」を緻密に加味し、予算管理表へリアルタイムに同期させる。この泥臭くも高尚なエンジニアリングを、Project VBAのオブジェクトモデルを骨の髄まで理解した上で実装する。
今回は、甘えを一切排した「プロダクション品質のコスト按分自動計算ロジック」をあなたに授けよう。
—
1. なぜ「単純なコスト集計」では実務で使い物にならないのか?
MS Projectのデフォルト機能や素朴なVBAコードでは、以下の致命的な罠(バグの温床)が存在する。
- 罠A: 計画コスト(Cost)と実コスト(Actual Cost)の混同
- タスクが遅延していても、予定通りのコストが計上されてしまい、財務部門からの監査で一発レッドカードを食らう。
- 罠B: リソース割り当て(Assignment)のライフサイクル無視
- Taskオブジェクト側だけでコストを計算すると、複数リソースが混在する複雑なアサインメント(時間配分、残業手当、標準単価の差異)がすべて均されてしまい、精度がゴミクズになる。
- 罠C: ゼロ除算とパフォーマンストラップ
- 数千行に及ぶWBSをループ処理する際、`.Assignments` コレクションに無造作にアクセスすると、COMのラウンドトリップが発生し、処理が数分で終わらない「動く産業廃棄物」が完成する。
これらを完全に克服するためには、`Assignment` オブジェクトを直接叩き、各リソースの稼働実績と進捗率(Work / Physical % Complete)を緻密に掛け合わせる必要がある。
—
2. 堅牢な設計思想:Assignmentオブジェクトの要塞化
今回のアーキテクチャの肝は以下の3点だ。
1. スコープの絞り込みとキャッシュ
- 無駄なプロパティアクセスを排除し、必要なメトリクス(Work, ActualWork, Cost等)を一網打尽に取得する。
2. 堅牢な例外・ゼロ除算ガード
- 工数がゼロのタスク、またはリソースがアサインされていない孤立タスクでVBAが沈黙(エラー終了)するのを防ぐ。
3. 外部連携(Excel予算管理表)へのアトミック書き込み
- Project側で計算したデータを、Excel側のテーブルへ一括転送し、データ不整合の余地を断つ。
—
3. 【コピペ即導入】プロダクション品質のVBAコード
以下のコードは、アクティブなプロジェクトの全タスク・全アサインメントを走査し、進捗率に応じた按分コストを算出して、イミディエイトウィンドウへの出力およびExcelへのデータ引き渡しを想定した堅牢な実装だ。
Option Explicit
‘ ==============================================================================
‘ 処理名 : CalculateAndExportEarnedCost
‘ 概要 : リソースの割り当て(Assignment)単位で進捗率を考慮した実コストを算出し、
予算管理の精度を極限まで高めるプロシージャ。
‘ ==============================================================================
Public Sub CalculateAndExportEarnedCost()
‘ パフォーマンス爆速化のための定石
Dim originalCalc As Long
originalCalc = Application.Calculation
Application.Calculation = pjManual
Application.ScreenUpdating = False
On Error GoTo ErrorHandler
Dim t As Task
Dim a As Assignment
‘ 集計用変数
Dim totalProjectCost As Currency
Dim totalEarnedCost As Currency
totalProjectCost = 0
totalEarnedCost = 0
Debug.Print “=== リソースコスト按分計算開始: ” & Now & ” ===”
‘ タスクループ(サマリータスクやマイルストーンのノイズを適切にハンドリング)
For Each t In ActiveProject.Tasks
If Not t Is Nothing Then
‘ 外部リファレンスや削除済みタスクの除外
If t.ExternalTask = False And t.Active = True Then
‘ アサインメントが存在しないタスクはスキップ
If t.Assignments.Count > 0 Then
For Each a In t.Assignments
‘ リソースが割り当てられていないプレースホルダー等の除外
If Not a.Resource Is Nothing Then
‘ — コア計算ロジック —
‘ 計画コスト (Baseline Cost または Cost)
Dim plannedCost As Currency
plannedCost = a.Cost
‘ 進捗率の取得 (ここでは工数ベースの進捗 % Work Complete を採用)
‘ ※物理進捗を使う場合は t.PhysicalPercentComplete 等に差し替えよ
Dim workPercentComplete As Double
workPercentComplete = a.PercentWorkComplete / 100#
‘ 進捗率を考慮した按分コスト(実質的発生コストの算定)
Dim earnedCost As Currency
earnedCost = plannedCost workPercentComplete
‘ 累計加算
totalProjectCost = totalProjectCost + plannedCost
totalEarnedCost = totalEarnedCost + earnedCost
‘ デバッグ出力(実務ではここにExcel書き込み処理やDB連携を挿入する)
‘ Debug.Print “Task: ” & t.Name & ” | Resource: ” & a.ResourceName & _
‘ ” | 計画: ” & plannedCost & ” | 進捗: ” & (workPercentComplete 100) & “%” & _
‘ ” | 按分コスト: ” & earnedCost
End If
Next a
End If
End If
End If
Next t
Debug.Print “————————————————–”
Debug.Print “【総計画コスト】: ” & Format(totalProjectCost, “#,
0 円”)
Debug.Print “【進捗按分コスト】: ” & Format(totalEarnedCost, “#,
0 円”)
Debug.Print “=== 処理正常終了: ” & Now & ” ===”
‘ 正常終了時のクリーンアップ
GoTo Finally
ErrorHandler:
MsgBox “予期せぬエラーが発生しました。” & vbCrLf & _
“Error No: ” & Err.Number & vbCrLf & _
“Description: ” & Err.Description, vbCritical, “Project VBA 異常終了”
Finally:
‘ 環境を必ず元の状態に戻す(これ職人の鉄則)
Application.Calculation = originalCalc
Application.ScreenUpdating = True
End Sub
—
4. チーフアーキテクトからの実装上の忠告
このコードを現場に導入する際、以下のポイントに留意しろ。甘い実装は必ず現場で破綻する。
① パフォーマンス制御の絶対遵守
コードの最初と最後で `Application.Calculation = pjManual` と `Application.ScreenUpdating = False` を挟んでいる。数千件のタスクを持つMS Projectでこれを怠ると、画面描画と自動再計算の嵐でPCがフリーズし、プロジェクトマネージャーからの冷たい視線を浴びることになる。例外処理(`ErrorHandler`)のラベル内で確実に元の設定に戻す構造(トランザクション的な発想)を崩すな。
② 進捗率の定義(% Work Complete vs % Complete)
今回のコードではリソースの稼働実績に直結する `% Work Complete(工数の進捗率)` を採用した。もしプロジェクトの契約形態や社内ルールが「成果物ベースの物理進捗(Physical % Complete)」を強要する場合は、`a.PercentWorkComplete` の部分をタスク側の進捗プロパティに置き換えるか、アサインメント側のカスタムフィールドと同期させる設計変更を行え。
③ Excel / データベース連携時のトランザクション
このスクリプトで算出した `earnedCost` をExcelの予算管理シートやDB(SQL Server等)に飛ばす際は、セルの1つ1つに書き込むような愚行は避けるべきだ。
- 配列(Array)にデータを一度メモリ上で凝縮し、ExcelのRangeへ一括吐き出し(Bulk Insert)する
- ADO等を用いてトランザクションを張り、一括Commitする
このレベルの最適化ができて初めて「プロの業務自動化エンジニア」を名乗ることができる。
—
結び
プロジェクト管理は、感覚や気合で行うものではない。数学的根拠と、正確なオブジェクトライフサイクルの把握によってのみ統制される。
今回提供したAssignmentオブジェクトのハンドリング手法をあなたのプロジェクト管理基盤に組み込み、属人化されたどんぶり勘定のコスト管理を今すぐ駆逐してほしい。
健闘を祈る。
