added detection & deletion of shifts overlapping time off, added RLCZ maintenance shift planning, added removal of shifts from allshifts when removing a shift, fixed inaccurate debug messages

This commit is contained in:
2025-11-25 15:06:25 +01:00
parent 765bcdf1de
commit e83e935a3d

View File

@@ -57,10 +57,10 @@ function Set-Shift {
if($script:noplan -eq $false) { if($script:noplan -eq $false) {
$newShift = New-MgTeamScheduleShift -TeamId $teamID -BodyParameter $params -Headers @{ "MS-APP-ACTS-AS" = $userIdAdmin } $newShift = New-MgTeamScheduleShift -TeamId $teamID -BodyParameter $params -Headers @{ "MS-APP-ACTS-AS" = $userIdAdmin }
Write-Debug("{0} {1}: setting {2}'s shift - {3} {4}-{5}" -f $dayDate, $dayDate.DayOfWeek, $mail, $shiftName, $StartDate, $EndDate) Write-Debug("{0} {1}: setting {2}'s shift - {3} {4}-{5}" -f $dayDate.Date, $dayDate.DayOfWeek, $mail, $shiftName, $StartDate, $EndDate)
} }
else { else {
Write-Debug("{0} {1}: Not setting {2}'s shift - {3} {4}-{5} - running with -noplan" -f $dayDate, $dayDate.DayOfWeek, $mail, $shiftName, $StartDate, $EndDate) Write-Debug("{0} {1}: Not setting {2}'s shift - {3} {4}-{5} - running with -noplan" -f $dayDate.Date, $dayDate.DayOfWeek, $mail, $shiftName, $StartDate, $EndDate)
$newshift = 0 $newshift = 0
} }
@@ -71,15 +71,16 @@ function Set-Shift {
function Remove-Shift { function Remove-Shift {
param( param(
[PSCustomObject]$shift, [PSCustomObject]$shift,
[string]$teamID [string]$teamID,
[string]$removal_email
) )
if($script:noplan -eq $false) { if($script:noplan -eq $false) {
Write-Debug("{0} {1}: removing {2}'s shift - {2} {3}-{4}" -f $dayDate, $dayDate.DayOfWeek, $futureds_email, $shift.Notes, $shift.StartDateTime, $shift.EndDateTime) Write-Debug("{0} {1}: removing {2}'s shift - {3} {4}-{5}" -f $dayDate.Date, $dayDate.DayOfWeek, $removal_email, $shift.SharedShift.Notes, $shift.SharedShift.StartDateTime, $shift.SharedShift.EndDateTime)
Remove-MgTeamScheduleShift -ShiftId $shift.id -TeamId $teamID Remove-MgTeamScheduleShift -ShiftId $shift.id -TeamId $teamID
} }
else { else {
Write-Debug("{0} {1}: Not removing {2}'s shift - {2} {3}-{4} - running with -noplan" -f $dayDate, $dayDate.DayOfWeek, $futureds_email, $shift.Notes, $shift.StartDateTime, $shift.EndDateTime) Write-Debug("{0} {1}: Not removing {2}'s shift - {3} {4}-{5} - running with -noplan" -f $dayDate.Date, $dayDate.DayOfWeek, $removal_email, $shift.SharedShift.Notes, $shift.SharedShift.StartDateTime, $shift.SharedShift.EndDateTime)
} }
} }
@@ -92,7 +93,7 @@ function Invoke-HasTimeOff {
foreach ($toff in $timeoff) { foreach ($toff in $timeoff) {
if($toff.UserId -eq $UID) { if($toff.UserId -eq $UID) {
Write-Debug("{0} {1}: {2} has time off" -f $dayDate, $dayDate.DayOfWeek, $mail) Write-Debug("{0} {1}: {2} has time off" -f $dayDate.Date, $dayDate.DayOfWeek, $mail)
return $true return $true
break break
} }
@@ -108,7 +109,7 @@ function Invoke-HasShift {
foreach ($shift in $shifts) { foreach ($shift in $shifts) {
if($shift.UserId -eq $UID) { if($shift.UserId -eq $UID) {
Write-Debug("{0} {1}: {2} has a shift already - {3} {4}-{5}" -f $dayDate, $dayDate.DayOfWeek, $mail, $shift.SharedShift.Notes, $shift.SharedShift.StartDateTime, $shift.SharedShift.EndDateTime) Write-Debug("{0} {1}: {2} has a shift already - {3} {4}-{5}" -f $dayDate.Date, $dayDate.DayOfWeek, $mail, $shift.SharedShift.Notes, $shift.SharedShift.StartDateTime, $shift.SharedShift.EndDateTime)
return $true return $true
break break
} }
@@ -126,7 +127,7 @@ function Invoke-HasShiftorTimeOff {
foreach ($shift in $shifts) { foreach ($shift in $shifts) {
if($shift.UserId -eq $UID) { if($shift.UserId -eq $UID) {
Write-Debug("{0} {1}: {2} has a shift already - {3} {4}-{5}" -f $dayDate, $dayDate.DayOfWeek, $mail, $shift.SharedShift.Notes, $shift.SharedShift.StartDateTime, $shift.SharedShift.EndDateTime) Write-Debug("{0} {1}: {2} has a shift already - {3} {4}-{5}" -f $dayDate.Date, $dayDate.DayOfWeek, $mail, $shift.SharedShift.Notes, $shift.SharedShift.StartDateTime, $shift.SharedShift.EndDateTime)
return $true return $true
break break
} }
@@ -134,7 +135,7 @@ function Invoke-HasShiftorTimeOff {
foreach ($toff in $timeoff) { foreach ($toff in $timeoff) {
if($toff.UserId -eq $UID) { if($toff.UserId -eq $UID) {
Write-Debug("{0} {1}: {2} has time off" -f $dayDate, $dayDate.DayOfWeek, $mail) Write-Debug("{0} {1}: {2} has time off" -f $dayDate.Date, $dayDate.DayOfWeek, $mail)
return $true return $true
break break
} }
@@ -169,7 +170,6 @@ $allemails = $schedule.PSObject.Properties | ForEach-Object {
$_.Value.PSObject.Properties | ForEach-Object { $_.Value.PSObject.Properties | ForEach-Object {
if ($_.Name -in @("ds", "ho", "os", "ns")) { if ($_.Name -in @("ds", "ho", "os", "ns")) {
if ($_.Name -eq "os") { if ($_.Name -eq "os") {
# Collect the email field from objects
$_.Value | ForEach-Object { $_.email } $_.Value | ForEach-Object { $_.email }
} }
else { else {
@@ -200,6 +200,7 @@ $endSpanDate = Get-Date -Day $startSpanDate.AddDays($daysahead).Day -Month $star
$rlcz_mtnc_email = "jiri.kotlan@itego.cz" $rlcz_mtnc_email = "jiri.kotlan@itego.cz"
$rlcz_shift_reduction = -3 #How many hours does the next day shift get reduced by $rlcz_shift_reduction = -3 #How many hours does the next day shift get reduced by
$rlcz_maintenance_length = 4
# --------------------------- | MAIN SCRIPT | --------------------------- # --------------------------- | MAIN SCRIPT | ---------------------------
@@ -214,7 +215,7 @@ try {
if ($clear) { if ($clear) {
foreach ($shift in $allshifts) { foreach ($shift in $allshifts) {
if($shift.SharedShift.Notes -ne "RLCZ") { if($shift.SharedShift.Notes -ne "RLCZ") {
Remove-Shift -shift $shift -teamID $team.Id Remove-Shift -shift $shift -teamID $team.Id -removal_email "someone"
} }
} }
return return
@@ -230,7 +231,7 @@ try {
# ---| WEEKEND CHECK |--- # ---| WEEKEND CHECK |---
if($dayDate.DayOfWeek -in @("Saturday", "Sunday")) { if($dayDate.DayOfWeek -in @("Saturday", "Sunday")) {
Write-Debug("{0} {1}: skipping weekend day" -f $dayDate, $dayDate.DayOfWeek) Write-Debug("{0} {1}: skipping weekend day" -f $dayDate.Date, $dayDate.DayOfWeek)
continue continue
} }
@@ -238,7 +239,7 @@ try {
$holiday_response = (Invoke-WebRequest -Uri "https://svatky.steelants.cz/api/$($dayDate.ToString('yyyy-MM-dd'))" -Method GET -Headers $headers_holiday) | ConvertFrom-Json $holiday_response = (Invoke-WebRequest -Uri "https://svatky.steelants.cz/api/$($dayDate.ToString('yyyy-MM-dd'))" -Method GET -Headers $headers_holiday) | ConvertFrom-Json
if($holiday_response.isPublicHoliday) { if($holiday_response.isPublicHoliday) {
Write-Debug("{0} {1}: skipping holiday" -f $dayDate, $dayDate.DayOfWeek) Write-Debug("{0} {1}: skipping holiday" -f $dayDate.Date, $dayDate.DayOfWeek)
continue continue
} }
@@ -264,7 +265,7 @@ try {
# ---| TODAY'S SHIFTS AND TIME OFF |--- # ---| TODAY'S SHIFTS AND TIME OFF |---
$shifts_today = [Object[]] $allshifts | Where-Object -Filter { $shifts_today = [Object[]] $allshifts | Where-Object -Filter {
$_.schedulingGroupId -eq $group.Id -and $_.SharedShift.StartDateTime.ToString("yyyy-MM-dd HH:mm") -ge $dateStart.ToString("yyyy-MM-dd HH:mm") -and $_.SharedShift.EndDateTime.ToString("yyyy-MM-dd HH:mm") -le $dateEnd.ToString("yyyy-MM-dd HH:mm") $_.schedulingGroupId -eq $group.Id -and $_.SharedShift.StartDateTime.ToString("yyyy-MM-dd HH:mm") -ge $dateStart.ToString("yyyy-MM-dd HH:mm") -and $_.SharedShift.EndDateTime.ToString("yyyy-MM-dd HH:mm") -le $dateEnd.ToString("yyyy-MM-dd HH:mm")
} }
$timeoff_today = [Object[]] $timeoff_all | Where-Object { $timeoff_today = [Object[]] $timeoff_all | Where-Object {
@@ -276,21 +277,74 @@ try {
if ($null -eq $manual_dayshifts) { if ($null -eq $manual_dayshifts) {
$ds_shift_inplace = $false $ds_shift_inplace = $false
Write-Debug("{0} {1}: day shift not yet set" -f $dayDate, $dayDate.DayOfWeek) Write-Debug("{0} {1}: day shift not yet set" -f $dayDate.Date, $dayDate.DayOfWeek)
} }
else { else {
$ds_shift_inplace = $true $ds_shift_inplace = $true
Write-Debug("{0} {1}: day shift set already" -f $dayDate, $dayDate.DayOfWeek) Write-Debug("{0} {1}: day shift set already" -f $dayDate.Date, $dayDate.DayOfWeek)
} }
# ---| TEAM MEMBER LOOP |--- # ---| TEAM MEMBER LOOP |---
foreach($email in $allemails) { foreach($email in $allemails) {
$userId = $(Get-MgUser -Filter "UserPrincipalName eq '$email' or proxyAddresses/any(c:c eq 'smtp:$email')").Id $userId = $(Get-MgUser -Filter "UserPrincipalName eq '$email' or proxyAddresses/any(c:c eq 'smtp:$email')").Id
# ---| TIME OFF AND SHIFT OVERLAP CHECK |---
if(Invoke-HasTimeOff -UID $userId -timeoff $timeoff_today -mail $email) {
if(Invoke-HasShift -UID $userId -shifts $shifts_today -mail $email) {
Write-Debug("{0} {1}: {2} has approved time-off and a shift, checking overlap..." -f $dayDate.Date, $dayDate.DayOfWeek, $email)
# ---| IDENTIFY SHIFT AND TIME OFF VARIABLES |---
foreach($shift in $shifts_today) {
if($shift.UserId -eq $userId) {
$overlap_shift = $shift
}
}
foreach($timeoff in $timeoff_today) {
if($timeoff.UserId -eq $userId) {
$overlap_timeoff = $timeoff
}
}
if(($null -eq $overlap_shift) -or ($null -eq $overlap_timeoff)) {
Write-Debug("{0} {1}: {2} couldn't find the specific shift or time off, ignoring..." -f $dayDate.Date, $dayDate.DayOfWeek, $email)
continue
}
# ---| OVERLAP CHECK |---
if($overlap_shift.SharedShift.StartDateTime.ToString("yyyy-MM-dd HH:mm") -ge $overlap_timeoff.SharedTimeOff.StartDateTime.ToString("yyyy-MM-dd HH:mm")) {
Write-Debug("{0} {1}: {2} today's shift starts after today's time off starts..." -f $dayDate.Date, $dayDate.DayOfWeek, $email)
if($overlap_shift.SharedShift.StartDateTime.ToString("yyyy-MM-dd HH:mm") -lt $overlap_timeoff.SharedTimeOff.EndDateTime.ToString("yyyy-MM-dd HH:mm")) {
Write-Debug("{0} {1}: {2} today's shift starts before today's time off ends... overlap found" -f $dayDate.Date, $dayDate.DayOfWeek, $email)
Remove-Shift -shift $overlap_shift -teamID $team.Id -removal_email $email
$allshifts = $allshifts | Where-Object { $_.SharedShift.Id -ne $overlap_shift.SharedShift.Id }
}
else {
Write-Debug("{0} {1}: {2} today's shift starts after today's time off ends... no overlap" -f $dayDate.Date, $dayDate.DayOfWeek, $email)
}
}
}
}
# ---| RLCZ MAINTENANCE PLANNER |---
if($dayDate.DayOfWeek -eq 'Wednesday') {
if($email -eq $rlcz_mtnc_email) {
$tuesdaynumber = (1..$dayDate.Day | ForEach-Object {
(Get-Date -Year $dayDate.Year -Month $dayDate.Month -Day $_).DayOfWeek
} | Where-Object { $_ -eq 'Tuesday' }).Count
if($tuesdaynumber -ge 2 -and $tuesdaynumber -le 4) {
Write-Debug("{0} {1}: yesterday was Tuesday number {3}, planning RLCZ maintenance shift" -f $dayDate.Date, $dayDate.DayOfWeek, $email, $tuesdaynumber)
$rlcz_starttime = $dateEnd.AddHours(1)
$rlcz_endtime = $rlcz_starttime.AddHours($rlcz_maintenance_length)
$newshift = Set-Shift -userId $userId -groupID $group.id -shiftName "RLCZ" -StartDate $rlcz_starttime -EndDate $rlcz_endtime -color "yellow" -teamID $team.id -mail $email
$allshifts += [Object[]] $newshift
}
}
}
# ---| DAY SHIFT CHECK |--- # ---| DAY SHIFT CHECK |---
if($ds_shift_inplace -eq $false) { if($ds_shift_inplace -eq $false) {
if($email -eq $ds_email) { if($email -eq $ds_email) {
Write-Debug("{0} {1}: checking {2} for day shift availability..." -f $dayDate, $dayDate.DayOfWeek, $email) Write-Debug("{0} {1}: checking {2} for day shift availability..." -f $dayDate.Date, $dayDate.DayOfWeek, $email)
# ---| IF DAY SHIFT CAN BE ASSIGNED TO THE PROPER MEMEBER |--- # ---| IF DAY SHIFT CAN BE ASSIGNED TO THE PROPER MEMEBER |---
if((Invoke-HasShiftorTimeOff -UID $userId -shifts $shifts_today -timeoff $timeoff_today -mail $email) -eq $false) { if((Invoke-HasShiftorTimeOff -UID $userId -shifts $shifts_today -timeoff $timeoff_today -mail $email) -eq $false) {
@@ -312,7 +366,7 @@ try {
# ---| DAY SHIFT REPLACEMENT CHECK |--- # ---| DAY SHIFT REPLACEMENT CHECK |---
else { else {
Write-Debug("{0} {1}: looking ahead for a day shift replacement" -f $dayDate, $dayDate.DayOfWeek) Write-Debug("{0} {1}: looking ahead for a day shift replacement" -f $dayDate.Date, $dayDate.DayOfWeek)
# ---| FUTURE DAYS LOOP |--- # ---| FUTURE DAYS LOOP |---
for ($daysahead = 1; $daysahead -lt $ds_replace_daysahead; $daysahead++) { for ($daysahead = 1; $daysahead -lt $ds_replace_daysahead; $daysahead++) {
@@ -362,7 +416,8 @@ try {
foreach ($shift in $shifts_today) { foreach ($shift in $shifts_today) {
if($shift.UserId -eq $futureds_id -and $shift.SharedShift.Notes -ne "On-site") { if($shift.UserId -eq $futureds_id -and $shift.SharedShift.Notes -ne "On-site") {
# ---| REMOVE THE SHIFT |--- # ---| REMOVE THE SHIFT |---
Remove-Shift -shift $shift -teamID $team.Id Remove-Shift -shift $shift -teamID $team.Id -removal_email $futureds_email
$allshifts = $allshifts | Where-Object { $_.SharedShift.Id -ne $shift.SharedShift.Id }
# ---| HOME-OFFICE DAY SHIFT |--- # ---| HOME-OFFICE DAY SHIFT |---
if($futureds_email -in $ho_emails) { if($futureds_email -in $ho_emails) {
@@ -415,7 +470,7 @@ try {
# ---| NO-SHIFT CHECK |--- # ---| NO-SHIFT CHECK |---
if($email -in $ns_emails) { if($email -in $ns_emails) {
Write-Debug("{0} {1}: {2} has no-shift defined for today" -f $dayDate, $dayDate.DayOfWeek, $email) Write-Debug("{0} {1}: {2} has no-shift defined for today" -f $dayDate.Date, $dayDate.DayOfWeek, $email)
continue continue
} }