こんにちは!プロジェクト管理の現場で、日々「進捗と実績のズレ」に頭を悩ませていませんか?
「メンバーから上がってきた実績工数を入力したのに、なぜかトータルの工数(Work)が勝手に再計算されて狂ってしまう…」
「計画通りの工数で進んでいるはずなのに、ActualWork(実績工数)とWork(総工数)の同期がうまくいかない…」
MS Projectを実務で使いこなそうとした瞬間、誰もがこの「工数管理の魔物」にぶつかります。マクロの記録ボタンをポチるだけでは絶対にたどり着けない領域、それがResourceAssignment(リソース割り当て)オブジェクトの制御です。
今回は、数々の修羅場をくぐり抜けてきたシニアアーキテクトの私から、`Work`と`ActualWork`を完全に手足のように操り、リアルタイムで工数差異をねじ伏せるカスタム計算ロジックの極意を伝授します。ここさえクリアすれば、あなたのProject VBAのスキルは間違いなくプロの領域に到達しますよ。ついてきてくださいね!
—
1. 敵を知る:なぜMS Projectの工数は勝手に変わるのか?
まず、MS Projectのデータ構造の「お作法」を理解しましょう。ここを勘違いしていると、何度VBAを書いてもエラーや予期せぬ数値の書き換わりに泣かされます。
MS Projectの中には、以下の3つの重要な工数プロパティが存在します。
1. Work(仕事量 / 総工数):そのタスクを完了するために必要なトータルの時間。
2. ActualWork(実績工数):実際にそのリソースが作業に費やした時間。
3. RemainingWork(残存工数):これから作業が必要な時間。
MS Projectのデフォルトの挙動では、「ActualWorkを変更すると、RemainingWorkが自動調整され、結果としてWorkが変わる」、あるいはその逆の連鎖が発生します。
「計画値(Work)は固定したまま、実績(ActualWork)が入った分だけ綺麗に同期させたい!」という現場の要求を満たすには、VBAを使ってこの連鎖を論理的にコントロールしてあげる必要があるのです。
—
2. 基礎知識:ResourceAssignment オブジェクトへのアクセスルート
Project VBAの階層構造は、Excelとは少し違います。
Excelが `Workbook > Worksheet > Range` なら、Projectはこうです。
`Application > Project > Task > ResourceAssignment`
ひとつの「タスク」に複数の「リソース(人)」が割り当てられている場合、その交点に存在するオブジェクトが `ResourceAssignment` です。工数の保持者は、タスクそのものではなく、この「アサインメント」単位であることを絶対に忘れないでください。
—
3. 実践コード:工数を美しく同期させるカスタムロジック
それでは、現場でそのままコピペして使える実用的なVBAコードを公開します。
このコードは、選択中のタスクに紐づくリソースのアサインメントを走査し、「計画工数(Work)の枠内で、入力された実績工数(ActualWork)を正しく反映させ、残工数を綺麗に調停する」というスマートなロジックです。
Sub SyncWorkAndActualWork()
‘ ==============================================================================
‘ 【処理概要】
‘ 選択中タスクのリソース割り当てに対し、実績工数(ActualWork)と
‘ 総工数(Work)の整合性を保ちながらリアルタイムに差異を算出・同期するプロシージャ
‘ ==============================================================================
Dim tsk As Task
Dim assn As Assignment
Dim originalWork As Double
Dim actualWk As Double
Dim varianceWk As Double
‘ エラーハンドリングの基本
On Error GoTo ErrorHandler
‘ アクティブなプロジェクトが存在するかチェック
If ActiveProject.Tasks.Count = 0 Then
MsgBox “現在開かれているプロジェクトがありません。”, vbExclamation, “処理中断”
Exit Sub
End If
‘ 選択されているタスクをループ処理(複数選択にも対応)
For Each tsk In ActiveSelection.Tasks
‘ タスクがサマリー(親)タスク、またはマイルストーンの場合は対象外とする
If Not tsk.Summary And tsk.Milestone = False Then
‘ タスクに割り当てられている全てのリソース(Assignment)を走査
For Each assn In tsk.Assignments
‘ 1. 現在の総工数(Work)を分単位から時間単位に変換して保持(※Projectの内部単位は分)
originalWork = assn.Work / 60
‘ 2. 実績工数(ActualWork)を取得
actualWk = assn.ActualWork / 60
‘ — 【コアロジック】差異の算出とスマート同期 —
‘ 実績が入力されている場合の処理
If actualWk > 0 Then
‘ 例として:もし実績が総工数を超過している場合、Work側を自動拡張する安全策
If actualWk > originalWork Then
‘ 超過分を許容し、Workを実績値に合わせる
assn.Work = actualWk 60
originalWork = actualWk
End If
‘ 残存工数(RemainingWork)を「総工数 – 実績工数」で厳密に再計算・固定化
assn.RemainingWork = (originalWork – actualWk) 60
End If
‘ 3. 計画との差異(Variance)をカスタム計算してデバッグ出力(またはカスタム数値フィールドへ格納)
‘ ※今回はイミディエイトウィンドウにリアルタイム差異を出力
varianceWk = originalWork – (actualWk + (assn.RemainingWork / 60))
Debug.Print “タスク名: ” & tsk.Name & _
” | 担当者: ” & assn.ResourceName & _
” | 計画(Work): ” & originalWork & “h” & _
” | 実績(Actual): ” & actualWk & “h” & _
” | 差異: ” & varianceWk & “h”
Next assn
End If
Next tsk
MsgBox “工数の同期と差異計算が正常に完了しました。”, vbInformation, “完了”
Exit Sub
ErrorHandler:
MsgBox “予期せぬエラーが発生しました: ” & Err.Description, vbCritical, “エラー”
End Sub
—
4. コードのポイントと、陥りやすい罠の回避術
ここで、シニアエンジニアとしての重要なワンポイントアドバイスをいくつかお伝えします。
① Project内部単位は「分(Minutes)」である
コードの中で ` 60` や `/ 60` を頻出させていることに気づきましたか?
MS ProjectのVBAオブジェクト(`Work`, `ActualWork`, `RemainingWork`など)が保持している数値の内部単位は、実は「分(Minutes)」です。
画面上では「8時間(h)」と表示されていても、VBAから取得すると `480` という数値が返ってきます。ここを忘れてそのまま足し算引き算をすると、工数が文字通りケタ違いに爆発するので絶対に注意してください。
② サマリータスク(要約タスク)を触らない
プロジェクト全体の親であるサマリータスクに対して、直接 `Assignment` や `Work` を操作しようとすると、Projectは機嫌を損ねて実行時エラーを吐きます。
コード内で `If Not tsk.Summary` とガードを入れているのはそのためです。実務の自動化では、「末端の作業タスク(Leaf Task)だけを操作対象にする」のが鉄則です。
—
5. まとめ:ここをクリアすれば、Project VBAは怖くない!
今回は、`ResourceAssignment` オブジェクトをターゲットにして、`Work` と `ActualWork` の同期、そしてリアルタイムな差異算出を行うロジックを解説しました。
- プロジェクトの工数は「分単位」で保持されていること
- 工数の実体はタスクではなく「リソース割り当て(Assignment)」にあること
- 自動計算のトラップをVBAのロジックで逆手に取り、コントロールすること
この3つさえ押さえておけば、どんなに複雑なの大規模プロジェクトであっても、あなたの思い通りの工数管理システムをVBAで構築することができます。
「マクロの記録」の向こう側にある、オブジェクト指向的なプログラミングの世界へようこそ。ここをクリアしたあなたなら、もうProject VBAの基本はバッチリです!ぜひ現場の自動化に役立ててくださいね。
