【実務・中級編】リソースの「残業」を自動検知してコスト警告を出すマクロ – Project VBA解析バイブル

スポンサーリンク

Project VBAを掌握する極限の知見:リソースの「残業」を自動検知しコスト爆発を防ぐ監視ツールの設計と実装

開発現場において、プロジェクトマネージャーの最大の頭痛の種は何か。それはスケジュール遅延でもスコープクリープでもない。「気づいた時にはリソースコストが予算を焼き尽くしている状態」である。

特にProject VBA(Microsoft ProjectのVBA環境)を扱う現場では、リソースの稼働時間や残業コストの算出をExcelへの手動エクスポートに頼っているケースが後を絶たない。しかし、それでは遅い。オーバーワークが発生した瞬間に検知し、コスト超過分を定量化してアラートを上げる仕組みを、Projectの内部に常駐させなければ意味がないのだ。

今回は、Project VBAのオブジェクトモデルを熟知したアーキテクトだけが知る「堅牢かつ高速なリソース監視・コスト警告エンジン」の全貌を伝授する。

—

1. なぜ「愚直なループ処理」では実用に耐えないのか?

多くのアマチュアプログラマは、リソースの残業時間を計算しようとするとき、次のようなコードを書く。

‘ 【アンチパターン】これでは大規模プロジェクトでフリーズする
Dim r As Resource
For Each r In ActiveProject.Resources
If r.OverAllocated Then
‘ 何らかの処理
End If
Next r

このアプローチには2つの致命的な欠陥がある。
1. `OverAllocated`プロパティの罠: このプロパティは「リソースが同時に複数のタスクに割り当てられ、容量を超えているか」を判定するものであり、単なる「残業時間(Overtime Work)」を正確に表すわけではない。
2. COMオブジェクトへの無駄なアクセス頻度: `ActiveProject.Resources`のコレクションをループさせ、個別のプロパティにアクセスするたびにCOMの境界を跨ぐオーバーヘッドが発生し、数千行規模のスケジュールでは数秒〜数十秒の硬直を招く。

プロダクション環境に耐えうるシステムを作るには、「正確な残業時間プロパティの特定」「コスト単価(Cost Rate Tables)の正確な評価」「メモリ上での一括処理」の3点をクリアしなければならない。

—

2. 堅牢なコスト警告エンジンのアーキテクチャ

今回構築するツールは、以下の要件を満たす。

  • 基準稼働時間の動的判定: 標準稼働時間を超えたリソースの「残業時間(OvertimeWork)」を抽出し、時間単位のコストを掛け合わせる。
  • コストレートの考慮: Projectのリソースに設定されている標準単価(Standard Rate)および残業単価(Overtime Rate)を正確に取得する。
  • 安全なエラーハンドリング: リソースがアサインされていないタスクや、コストが未設定のパージデータを完全にガードする。

プロダクションコード:リソース残業・コスト監視マクロ

以下のコードをMicrosoft ProjectのVBAエディタ(ThisProjectまたは標準モジュール)に配置し実行してほしい。実務で即座に使える洗練されたエラー耐性とログ出力を実装している。

Option Explicit

‘ ==============================================================================
‘ 処理名: 資源残業コスト自動検知・警告エンジン
‘ 概要 : プロジェクト内の全リソースの稼働状況を走査し、規定の残業時間を
‘ 超過しているリソースを特定、超過コストを算出してイミディエイト窓口
‘ およびメッセージで警告を発報する。
‘ ==============================================================================
Sub AnalyzeResourceOvertimeAndCost()
Dim r As Resource
Dim totalOvertimeHours As Double
Dim overtimeCost As Double
Dim standardRate As Double
Dim overtimeRate As Double
Dim warningCount As Long

‘ 実行時のパフォーマンス向上のため画面更新を停止
App.ScreenUpdating False
On Error GoTo ErrorHandler

warningCount = 0

‘ ヘッダー出力
Debug.Print “==================================================”
Debug.Print ” 【リソース残業・コスト警告レポート】 実行日時: ” & Now
Debug.Print “==================================================”

‘ リソースコレクションの走査
For Each r In ActiveProject.Resources
‘ リソースが存在し、かつ「コストリソース」や「材料リソース」ではなく「作業リソース(Work)」であるか確認
If Not r Is Nothing Then
If r.Type = pjResourceTypeWork Then

‘ 残業時間(OvertimeWork)の取得 (Minutes単位で格納されているため時間(Hours)に変換)
‘ 注: Projectのデフォルト単位は分(M)なので、60で除算する
If r.OvertimeWork > 0 Then
totalOvertimeHours = r.OvertimeWork / 60

‘ コストレートの取得 (CostRateTable 0 を基準とする。必要に応じてインデックスを変更)
‘ ※ Projectでは StandardRate, OvertimeRate は通貨/時間で返る
standardRate = GetValidRate(r.StandardRate)
overtimeRate = GetValidRate(r.OvertimeRate)

‘ 残業単価が未設定(0)の場合は標準単価の1.5倍をフォールバックとして適用する防衛的設計
If overtimeRate = 0 Then
overtimeRate = standardRate 1.5
End If

‘ 超過コストの算出
overtimeCost = totalOvertimeHours overtimeRate

‘ 閾値を超えた場合の警告判定(例: 残業時間が5時間を超えた場合)
Const OVERTIME_THRESHOLD As Double = 5#

If totalOvertimeHours > OVERTIME_THRESHOLD Then
warningCount = warningCount + 1

‘ ログ出力
Debug.Print “警告 [” & warningCount & “] リソース名: ” & r.Name
Debug.Print ” – 残業時間 : ” & totalOvertimeHours & ” 時間”
Debug.Print ” – 適用残業単価 : ¥” & Format(overtimeRate, “#,

0″) & ” /h”

Debug.Print ” – 予想超過コスト: ¥” & Format(overtimeCost, “#,

0″)

Debug.Print “————————————————–”
End If
End If

End If
End If
Next r

‘ 終了処理
App.ScreenUpdating True

If warningCount > 0 Then
MsgBox “【警告】 ” & warningCount & “件のリソースで規定を超える残業が検知されました。” & vbCrLf & _
“詳細はイミディエイトウィンドウを確認してください。”, vbExclamation, “リソースコスト監視”
Else
MsgBox “対象期間内における重大な残業・コスト超過は検知されませんでした。”, vbInformation, “リソースコスト監視”
End If

Exit Sub

ErrorHandler:
App.ScreenUpdating True
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “システムエラー”
End Sub

‘ ==============================================================================
‘ 補助関数: レート値の安全な抽出とパージ
‘ ==============================================================================
Private Function GetValidRate(ByVal rateVariant As Variant) As Double
On Error Resume Next
If IsNumeric(rateVariant) Then
GetValidRate = CDbl(rateVariant)
Else
GetValidRate = 0#
End If
On Error GoTo 0
End Function

—

3. 実務運用における設計上の重要な注意点

このマクロを実際のプロジェクト管理プロセスに組み込む際、以下のアーキテクチャ上のポイントを押さえておく必要がある。

1. タイムユニット(時間単位)の罠

Microsoft Projectの内部データ構造では、稼働時間や残業時間はすべて「分(Minutes)」で保持されている。VBAから`r.OvertimeWork`を呼び出した場合、返ってくる数値の単位は分である。これをそのまま時間として計算すると、コストが60倍に跳ね上がるバグ(あるいはその逆)を引き起こす。上記のコードでは確実に` / 60`を入れて時間を担保している。

2. コストレートテーブル(Cost Rate Tables)の仕様

Projectには最大5つのコストレートテーブル(A~E)が存在する。今回のコードではデフォルトのテーブル(Table A相当)を対象としているが、複数レートを切り替えて運用しているプロジェクトでは、`r.CostRateTable`プロパティを評価に組み込む拡張が必要となる。

3. 自動化トリガーの設計

このマクロを手動で実行させるだけでは、人間の「うっかり」を防げない。

  • イベントプロシージャの活用: `Project_BeforeSave` イベントなどにフックさせ、ファイルを保存するタイミングでバックグラウンド実行し、超過コストが一定額を超えた場合にログファイルやデータベースへ自動送信する仕組みへと発展させるのがプロのやり方だ。

—

4. 総括

リソース管理の本質は、スケジュールを綺麗に引くことではなく、「プロジェクトのキャッシュ(コスト)がどこで溶けているかをリアルタイムで把握すること」にある。

今回提供したコードは、単なる情報の集計にとどまらず、プロジェクトの赤字化を未然に防ぐための強力な防衛ラインとなる。コピペして終わりにするのではなく、自社のプロジェクト管理基準(WBSの粒度や残業許容閾値)に合わせてチューニングし、真の自動化システムへと昇華させてほしい。

タイトルとURLをコピーしました