Sub Distribute_User_Stories()
'
' Written by Sebastian Krug, AIM, Deloitte Consulting GmbH
' Macro for distribution of user stories with given mapping
'
Dim epics As Worksheet, epic_mapping As Worksheet, sprintSheet As Worksheet
Dim epicFoundInMapping As Boolean
Dim epicFoundInOriginalList As Boolean
Dim userStoryIsAssigned As Boolean
Dim epic_dict As New Scripting.Dictionary
Dim priceList As Object
Set priceList = CreateObject("System.Collections.ArrayList")
Set epics = ThisWorkbook.Sheets("EPICs")
Set epic_mapping = ThisWorkbook.Sheets("EPIC Refinement")
Set sprintSheet = ThisWorkbook.Sheets("Sprint 11") ' ==> ANPASSEN FÜR ANDEREN SPRINT!
' Add prices for T-Shirt sizes to priceList
priceList.Add epics.Cells(2, 6) 'S
priceList.Add epics.Cells(2, 8) 'M
priceList.Add epics.Cells(2, 9) 'L
priceList.Add epics.Cells(2, 10) 'XL
priceList.Add epics.Cells(2, 11) 'XXL/2XL
'Iterate through sprint epic IDs
For Counter_sprintSheet = 1 To sprintSheet.UsedRange.Rows.Count
epicFoundInMapping = False
epicFoundInOriginalList = False
userStoryIsAssigned = False
Set epic_link = sprintSheet.Cells(Counter_sprintSheet, 23)
Set Status = sprintSheet.Cells(Counter_sprintSheet, 7)
Set Provider = sprintSheet.Cells(Counter_sprintSheet, 13)
Set size = sprintSheet.Cells(Counter_sprintSheet, 15)
If (Status = "Resolved" Or Status = "Closed") And Provider = "DT-HuP" And epic_link <> "" Then
WriteLogEntry ("The T-Shirt Size of " + epic_link.Value + " is " + size.Value + " and the status is '" + Status.Value + "'")
' Iterate through epic mapping
For Counter_refinement = 1 To epic_mapping.UsedRange.Rows.Count
Set epic_new = epic_mapping.Cells(Counter_refinement, 2)
If epic_new = epic_link Then 'epic found is mapping
epicFoundInMapping = True
Set epic_original = epic_mapping.Cells(Counter_refinement, 1)
Set flag_Merge = epic_mapping.Cells(Counter_refinement, 3)
Set flag_Split = epic_mapping.Cells(Counter_refinement, 4)
WriteLogEntry ("Epic link " + epic_link.Value + " found in mapping and is mapped to " + epic_original.Value + ".")
If flag_Merge = "" And flag_Split = "" Then
' 1-to-1 mapping
WriteLogEntry ("1-to-1 conversion from " + epic_new.Value + " to " + epic_original.Value)
For Counter_epics = 1 To epics.UsedRange.Rows.Count
Set epic = epics.Cells(Counter_epics, 2)
If epic = epic_original Then
epicFoundInOriginalList = True
WriteLogEntry ("Old Epic from mapping (" + epic_original.Value + ") found in EPICs list.")
Set epic_volume = epics.Cells(Counter_epics, 5)
Set volume_available = epics.Cells(Counter_epics, 6)
If volume_available - getBlockedVolume(epic_dict, epic.Value, priceList) - getPrice(size.Value, priceList) >= 0 Then
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " - " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " (volume blocked by previous assignments) > " + Str(getPrice(size.Value, priceList)) + ". Adding User Story with T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Set epic_dict = addTShirtSize(epic_dict, epic.Value, size.Value)
userStoryIsAssigned = True
Else
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " minus blocked volume " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " is NOT SUFFICIENT to cover the price of the T-Shirt size of " + Str(getPrice(size.Value, priceList)) + ".")
WriteLogEntry ("Adding User Story with T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Set epic_dict = addTShirtSize(epic_dict, epic.Value, size.Value)
userStoryIsAssigned = True
End If
End If
Next
ElseIf flag_Split = "Split" Then
WriteLogEntry ("Split of " + epic_original.Value + " into " + epic_new.Value + " and others. Unique assignment possible ...")
For Counter_epics = 1 To epics.UsedRange.Rows.Count
Set epic = epics.Cells(Counter_epics, 2)
If epic = epic_original Then
epicFoundInOriginalList = True
WriteLogEntry ("Old Epic from mapping (" + epic_original.Value + ") found in EPICs list.")
Set epic_volume = epics.Cells(Counter_epics, 5)
Set volume_available = epics.Cells(Counter_epics, 6)
If volume_available - getBlockedVolume(epic_dict, epic.Value, priceList) - getPrice(size.Value, priceList) >= 0 Then
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " - " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " (volume blocked by previous assignments) > " + Str(getPrice(size.Value, priceList)) + ". Adding User Story with T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Set epic_dict = addTShirtSize(epic_dict, epic.Value, size.Value)
userStoryIsAssigned = True
Else
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " minus blocked volume " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " is NOT SUFFICIENT to cover the price of the T-Shirt size of " + Str(getPrice(size.Value, priceList)) + ".")
WriteLogEntry ("Adding User Story with T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Set epic_dict = addTShirtSize(epic_dict, epic.Value, size.Value)
userStoryIsAssigned = True
End If
End If
Next
ElseIf flag_Merge = "Merge" Then
WriteLogEntry ("Merge of " + epic_original.Value + " and other into " + epic_new.Value + ". No unique assigment possible ... ")
WriteLogEntry ("Start searching for possible epics for assigment ...")
For Counter_epics = 1 To epics.UsedRange.Rows.Count
Set epic = epics.Cells(Counter_epics, 2)
If epic = epic_original Then
epicFoundInOriginalList = True
WriteLogEntry ("Old Epic from mapping (" + epic_original.Value + ") found in EPICs list.")
If userStoryIsAssigned = False Then
Set epic_volume = epics.Cells(Counter_epics, 5)
Set volume_available = epics.Cells(Counter_epics, 6)
If volume_available - getBlockedVolume(epic_dict, epic.Value, priceList) - getPrice(size.Value, priceList) >= 0 Then
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " - " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " (volume blocked by previous assignments) > " + Str(getPrice(size.Value, priceList)) + ". Adding User Story with T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Set epic_dict = addTShirtSize(epic_dict, epic.Value, size.Value)
userStoryIsAssigned = True
Else
If epic_new = epic_mapping.Cells(Counter_refinement + 1, 2) Then
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " minus blocked volume " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " is NOT SUFFICIENT to cover the price of the T-Shirt size of " + Str(getPrice(size.Value, priceList)) + ". Cannot add T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Else
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " minus blocked volume " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " is NOT SUFFICIENT to cover the price of the T-Shirt size of " + Str(getPrice(size.Value, priceList)) + ".")
WriteLogEntry ("Adding User Story with T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Set epic_dict = addTShirtSize(epic_dict, epic.Value, size.Value)
userStoryIsAssigned = True
End If
End If
Else
WriteLogEntry ("Skipping user story because it has already been assigned to a previous epic.")
End If
End If
Next
Else
WriteLogEntry ("Mapping condition not fulfilled. please check.")
End If
' Else
' WriteLogEntry ("Epic link " + epic_link.Value + " not found in mapping.")
End If
Next
If epicFoundInMapping = False Then
WriteLogEntry ("Epic link " + epic_link.Value + " not found in mapping. Searching in original epic list ...")
For Counter_epics = 1 To epics.UsedRange.Rows.Count
Set epic = epics.Cells(Counter_epics, 2)
If epic = epic_link Then
epicFoundInOriginalList = True
WriteLogEntry ("Epic link " + epic_link.Value + " found in EPICs list.")
Set epic_volume = epics.Cells(Counter_epics, 5)
Set volume_available = epics.Cells(Counter_epics, 6)
If volume_available - getBlockedVolume(epic_dict, epic.Value, priceList) - getPrice(size.Value, priceList) >= 0 Then
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " - " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " (volume blocked by previous assignments) > " + Str(getPrice(size.Value, priceList)) + ". Adding User Story with T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
Set epic_dict = addTShirtSize(epic_dict, epic.Value, size.Value)
userStoryIsAssigned = True
Else
WriteLogEntry ("Available volume =" + Str(volume_available.Value) + " minus blocked volume " + Str(getBlockedVolume(epic_dict, epic.Value, priceList)) + " is NOT SUFFICIENT to cover the price of the T-Shirt size of " + Str(getPrice(size.Value, priceList)) + ". Cannot add T-Shirt size " + size.Value + " to epic " + epic.Value + ".")
End If
End If
Next
If epicFoundInOriginalList = False Then WriteLogEntry ("Epic link " + epic_link.Value + " also not found in original list. No assignment possible ...")
End If
If userStoryIsAssigned = Flase Then
WriteLogEntry ("User story " + epic_link + " could not be assigned to an epic.")
End If
WriteLogEntry ("--------------------------------------------------------------------------------")
End If
Next
WriteLogEntry ("############################################################## Results #######################################################################################")
Dim counterAssignedUserStories As Integer
counterAssignedUserStories = 0
Dim k As Variant
For Each k In epic_dict.Keys
WriteLogEntry (k + " --> S =" + Str(epic_dict(k)(0)) + ", M =" + Str(epic_dict(k)(1)) + ", L =" + Str(epic_dict(k)(2)) + ", XL =" + Str(epic_dict(k)(3)) + ", XXL =" + Str(epic_dict(k)(4)))
counterAssignedUserStories = counterAssignedUserStories + epic_dict(k)(0) + epic_dict(k)(1) + epic_dict(k)(2) + epic_dict(k)(3) + epic_dict(k)(4)
Next k
WriteLogEntry (Str(counterAssignedUserStories) + " has been assigned.")
WriteLogEntry ("##############################################################################################################################################################")
' Write results to cells
' iterate again through dict and write list values to cells
For Each k In epic_dict.Keys
For Counter_epics = 1 To epics.UsedRange.Rows.Count
Set epic = epics.Cells(Counter_epics, 2)
If epic = k Then
epics.range("BL" & Counter_epics).Value = epic_dict(k)(0) 'S ' ==> ANPASSEN FÜR ANDEREN SPRINT!
epics.range("BM" & Counter_epics).Value = epic_dict(k)(1) 'M ' ==> ANPASSEN FÜR ANDEREN SPRINT!
epics.range("BN" & Counter_epics).Value = epic_dict(k)(2) 'L ' ==> ANPASSEN FÜR ANDEREN SPRINT!
epics.range("BO" & Counter_epics).Value = epic_dict(k)(3) 'XL ' ==> ANPASSEN FÜR ANDEREN SPRINT!
epics.range("BP" & Counter_epics).Value = epic_dict(k)(4) 'XXL ' ==> ANPASSEN FÜR ANDEREN SPRINT!
End If
Next
counterAssignedUserStories = counterAssignedUserStories + epic_dict(k)(0) + epic_dict(k)(1) + epic_dict(k)(2) + epic_dict(k)(3) + epic_dict(k)(4)
Next k
MsgBox "User Stories have been distributed."
End Sub
Function getPrice(s As String, priceList As Object) As Double
Dim p As Double
If s = "S" Then
p = priceList(0)
ElseIf s = "M" Then
p = priceList(1)
ElseIf s = "L" Then
p = priceList(2)
ElseIf s = "XL" Then
p = priceList(3)
ElseIf s = "XXL" Or s = "2XL" Then
p = priceList(4)
Else
WriteLogEntry ("Cannot get price of T-Shirt Size. Size '" + s + "' is invalid.")
End If
getPrice = p
End Function
Function getBlockedVolume(d As Dictionary, epic As String, priceList As Object) As Double
Dim p As Double
p = 0
If d.Exists(epic) Then
For i = 0 To 4
p = p + CDbl(d(epic)(i)) * CDbl(priceList(i))
Next
End If
getBlockedVolume = p
End Function
Function addTShirtSize(dict As Dictionary, key As String, size As String) As Dictionary
Dim vArray As Variant
Dim index As Integer
ReDim vArray(0 To 4)
If dict.Exists(key) Then
If size = "S" Then
index = 0
ElseIf size = "M" Then
index = 1
ElseIf size = "L" Then
index = 2
ElseIf size = "XL" Then
index = 3
ElseIf size = "XXL" Or size = "2XL" Then
index = 4
Else
WriteLogEntry ("Cannot store T-Shirt Size. Size '" + size + "' is invalid.")
End If
vArray = dict(key)
vArray(index) = vArray(index) + 1
dict(key) = vArray
Else
If size = "S" Then
dict.Add key, Array(1, 0, 0, 0, 0)
ElseIf size = "M" Then
dict.Add key, Array(0, 1, 0, 0, 0)
ElseIf size = "L" Then
dict.Add key, Array(0, 0, 1, 0, 0)
ElseIf size = "XL" Then
dict.Add key, Array(0, 0, 0, 1, 0)
ElseIf size = "XXL" Or size = "2XL" Then
dict.Add key, Array(0, 0, 0, 0, 1)
Else
WriteLogEntry ("Cannot store T-Shirt Size. Size '" + size + "' is invalid.")
End If
End If
Set addTShirtSize = dict
End Function
'Function Get_Column_Index(columnNumber As Integer) As Integer
' Dim dividend As Integer
' Set dividend = columnNumber
' Dim columnName As String
' Dim modulo As Integer
' While dividend > 0
' modulo = (dividend - 1) Mod 26
' columnName = Convert.ToChar(65 + modulo).ToString() & columnName
' dividend = CInt((dividend - modulo) / 26)
' End While
' Console.WriteLine (columnName.ToString)
' result = columnName
'End Function
Sub WriteLogEntry(logMessage As String)
Dim pathLogFile As String
pathLogFile = "C:\Users\rueschmidt\Desktop\Log.txt"
Open pathLogFile For Append As #1
Write #1, DateTime.Now & " -- " & logMessage
Close #1
End Sub
Sub printSprintResults(d As Dictionary)
Dim k As Variant
For Each k In d.Keys
WriteLogEntry (k + " --> " + Str(d(k)(0)) + ", " + Str(d(k)(1)) + ", " + Str(d(k)(2)) + ", " + Str(d(k)(3)) + ", " + Str(d(k)(4)))
Next k
End Sub