Option Explicit
Public Sub 番号転記()
Dim sh1 As Worksheet 'Sheet1
Dim sh2 As Worksheet 'Sheet2
Dim st_day As Variant '月初日
Dim en_day As Variant '月末日
Dim flag As Boolean
Dim maxrow1 As Long 'Sheet1の最大行数
Dim maxrow2 As Long 'Sheet2の最大行数
Dim row1 As Long
Dim row2 As Long
Dim col2 As Long
Dim i As Long
Dim pcount As Long '登録人数
Dim dicT As Object 'dictionary キー:担当者 値:Sheet2の行番号
Dim arr As Variant 'dictionaryの値(arr(0)=行番号,arr(1)=日付,arr(2)=番号,arr(3)=段数)
Dim key As Variant 'キー(担当者)
Dim wdate As Variant
Dim wno As Long
Dim dd As Long
Set dicT = CreateObject("Scripting.Dictionary")
Set sh1 = Worksheets("Sheet1")
Set sh2 = Worksheets("Sheet2")
'開始日取得
st_day = sh2.Cells(1, "B").Value
If IsDate(st_day) = True Then
If day(st_day) = 1 Then
flag = True
End If
End If
If flag = False Then
MsgBox ("Sheet2 B2日付不正")
Exit Sub
End If
'月末日取得
en_day = GetLastDay(st_day)
maxrow2 = sh2.Cells(Rows.count, "A").End(xlUp).Row '最終行を求める
If maxrow2 < 5 Then Exit Sub
If (maxrow2 - 5) Mod 4 <> 0 Then
MsgBox ("Sheet2 A列最大行数エラー")
Exit Sub
End If
pcount = ((maxrow2 - 5) \ 4) + 1
'Sheet2の担当者を記憶
For i = 1 To pcount
row2 = 5 + (i - 1) * 4
key = sh2.Cells(row2, "A").Value
If dicT.exists(key) = True Then
MsgBox ("Sheet2 重複担当者:" & key)
Exit Sub
End If
arr = Array(row2, 0, 0, 0)
dicT(key) = arr
Next
'Sheet2の初期化
For i = 1 To pcount
row2 = 5 + (i - 1) * 4
For dd = 1 To day(en_day)
col2 = 2 + (dd - 1) * 4
sh2.Cells(row2, col2 + 1).ClearContents '1段目開始番号
sh2.Cells(row2, col2 + 3).ClearContents '1段目終了番号
sh2.Cells(row2 + 1, col2 + 1).ClearContents '2段目開始番号
sh2.Cells(row2 + 1, col2 + 3).ClearContents '2段目終了番号
sh2.Cells(row2 + 2, col2 + 1).ClearContents '3段目開始番号
sh2.Cells(row2 + 2, col2 + 3).ClearContents '3段目終了番号
sh2.Cells(row2 + 3, col2 + 3).ClearContents '小計
Next
Next
'Sheet1を最終行まで処理する
maxrow1 = sh1.Cells(Rows.count, "A").End(xlUp).Row '最終行を求める
For row1 = 2 To maxrow1
wno = sh1.Cells(row1, "A").Value '番号
wdate = sh1.Cells(row1, "C").Value '日付
key = sh1.Cells(row1, "D").Value '担当者
If dicT.exists(key) = False Then
Call ErrorMsg(sh1, row1, "担当者未登録:" & key)
End If
flag = False
If IsDate(wdate) = True And wdate >= st_day And wdate <= en_day Then flag = True
If flag = False Then
Call ErrorMsg(sh1, row1, "日付不正:" & wdate)
End If
arr = dicT(key)
'行番号、列番号決定
row2 = arr(0)
col2 = 2 + (wdate - st_day) * 4
'日付戻りチェック
If arr(1) > 0 And wdate < arr(1) Then
Call ErrorMsg(sh1, row1, "日付戻り発生:" & wdate)
End If
'番号戻りチェック
If arr(2) > 0 And wno <= arr(2) Then
Call ErrorMsg(sh1, row1, "番号戻り発生:" & wno)
End If
'日付変更発生時
If wdate > arr(1) Then
arr(1) = wdate '日付更新
arr(2) = wno '番号更新
arr(3) = 1 '段数設定
sh2.Cells(row2 + arr(3) - 1, col2 + 1).Value = wno '開始番号
sh2.Cells(row2 + arr(3) - 1, col2 + 3).Value = wno '終了番号
Else
'日付が前回と同じ場合、
'番号に飛びがないなら、終了番号のみ更新
If arr(2) + 1 = wno Then
sh2.Cells(row2 + arr(3) - 1, col2 + 3).Value = wno '終了番号
Else
'番号が飛んでいるなら、次の段へ移動
arr(3) = arr(3) + 1
If arr(3) > 3 Then
Call ErrorMsg(sh1, row1, "段数オーバー")
End If
sh2.Cells(row2 + arr(3) - 1, col2 + 1).Value = wno '開始番号
sh2.Cells(row2 + arr(3) - 1, col2 + 3).Value = wno '終了番号
End If
arr(2) = wno '番号更新(日付は更新不要、段数は設定済み)
End If
dicT(key) = arr '値を戻す
'計更新
sh2.Cells(row2 + 3, col2 + 3).Value = sh2.Cells(row2 + 3, col2 + 3).Value + 1
Next
MsgBox ("完了")
End Sub
'エラーメッセージ出力&停止
Private Sub ErrorMsg(ByVal ws As Worksheet, ByVal wrow As Long, ByVal msg As String)
MsgBox ("Sheet1 " & wrow & "行 " & msg)
ws.Activate
ws.Cells(wrow, 1).Select
End
End Sub
'月末日取得
Private Function GetLastDay(ByVal st_day As Variant) As Variant
Dim yyyy As Long
Dim mm As Long
Dim wday As Date
yyyy = Year(st_day)
mm = Month(st_day)
mm = mm + 1
If mm > 12 Then
yyyy = yyyy + 1
mm = 1
End If
wday = DateSerial(yyyy, mm, 1)
GetLastDay = wday - 1
End Function