The code for the macro is split into a couple of different bits, the main Sub is the CutListHandler - this is the function called when the generate cutlist button is pressed:
Sub CutListHandler()
Dim ws As Worksheet: Set ws = ThisWorkbook.Sheets("Cut List")
'Set kerf
Dim kerf As String
kerf = ws.Cells(2, 12)
'Set output last row
Dim lastRow As Long
lastRow = 0
Dim x As Integer
'First do the available materials table
'Subtract the header rows from the number of filled table rows
Dim NumRows As Long
NumRows = ws.Range("A" & Rows.Count).End(xlUp).Row - 3
' Get a collection of all of the material types
Dim MaterialsCol As New Collection
Set MaterialsCol = MaterialsList(ws, "D" & x + 4 & ":" & "D" & NumRows + 4)
For Each Material In MaterialsCol
If Len((Material)) Then
Dim Parameters As Collection
Set Parameters = GenerateParameters((Material), ws, NumRows)
If Len(Parameters("availableStock")) And Len(Parameters("desiredPieces")) Then
Dim Response As WebResponse
Set Response = GenerateCutlist(Parameters("availableStock"), Parameters("desiredPieces"), kerf)
lastRow = ResponseOutput(Response, ws, lastRow)
End If
End If
Next
End Sub
The first custom function is the MaterialsList function, which gets the available materials from the table in your sheet:
'Get a unique list of materials
Function MaterialsList(ws As Worksheet, MaterialListRange As String) As Collection
Dim MaterialsListColumn As Range: Set MaterialsListColumn = ws.Range(MaterialListRange)
Dim MaterialsDictionary As New Dictionary
For Each c In ws.Range(MaterialListRange)
If MaterialsDictionary.Exists(c.Value) = False Then
MaterialsDictionary.Add c.Value, 1
ElseIf MaterialsDictionary.Exists(c.Value) Then
MaterialsDictionary(c.Value) = MaterialsDictionary(c.Value) + 1
End If
Next c
Set MaterialsList = New Collection
With MaterialsDictionary
For Each k In .Keys
MaterialsList.Add k
Next k
End With
End Function
The next function - GenerateParameters - makes the parameters array to be passed to the cutlist API:
'Generate the parameter strings (available and products) for a given material type
Function GenerateParameters(Material As String, ws As Worksheet, NumRows As Long) As Collection
Dim materials() As String
'ReDim materials(NumRows, 4)
Dim x As Long: x = 0
' Count the number of available boards of the passed material type
For Each c In ws.Range("A" & x + 4 & ":" & "A" & NumRows + 4)
If c.Offset(0, 3) = Material Then
x = x + 1
End If
Next c
'Create an array to hold all of the material boards
ReDim materials(x, 4)
x = 0
'Fill the array with parameter data
For Each c In ws.Range("A" & x + 4 & ":" & "A" & NumRows + 4)
If c.Offset(0, 3) = Material Then
materials(x, 0) = "'name': """ & c & """"
materials(x, 1) = "'length': " & c.Offset(0, 2)
materials(x, 2) = "'quantity': -1"
materials(x, 3) = "'cost': """ & c.Offset(0, 4) & """"
x = x + 1
End If
Next c
'Turn that array into an API parameter string
Dim joinedInfo() As String
ReDim joinedInfo(x)
For i = 0 To x - 1
For j = 0 To 3
If j = 0 Then
joinedInfo(i) = "{" & materials(i, j)
Else
joinedInfo(i) = joinedInfo(i) & "," & materials(i, j)
End If
Next j
joinedInfo(i) = joinedInfo(i) & "}"
Next i
Dim availableStock As String: availableStock = "[" & Left(Join(joinedInfo, ","), Len(Join(joinedInfo, ",")) - 1) & "]"
Debug.Print (availableStock)
'Then do the desired pieces table
'Subtract the header rows from the number of filled table rows
NumRows = ws.Range("G" & Rows.Count).End(xlUp).Row - 3
x = 0
Dim Products() As String
For Each c In ws.Range("G" & x + 4 & ":" & "G" & NumRows + 4)
If c.Offset(0, 2) = Material Then
x = x + 1
End If
Next c
If x Then
ReDim Products(x, 2)
x = 0
For Each c In ws.Range("G" & x + 4 & ":" & "G" & NumRows + 4)
If c.Offset(0, 2) = Material Then
Products(x, 0) = "'length': " & c
Products(x, 1) = "'quantity': " & c.Offset(0, 1)
x = x + 1
End If
Next c
ReDim joinedInfo(x)
For i = 0 To x - 1
For j = 0 To 1
If j = 0 Then
joinedInfo(i) = "{" & Products(i, j)
Else
joinedInfo(i) = joinedInfo(i) & "," & Products(i, j)
End If
Next j
joinedInfo(i) = joinedInfo(i) & "}"
Next i
Dim desiredPieces As String: desiredPieces = "[" & Left(Join(joinedInfo, ","), Len(Join(joinedInfo, ",")) - 1) & "]"
Else
desiredPieces = ""
End If
Debug.Print (desiredPieces)
Set GenerateParameters = New Collection
GenerateParameters.Add availableStock, "availableStock"
GenerateParameters.Add desiredPieces, "desiredPieces"
End Function
GenerateCutlist is the actual API calling function, it passes neccessary data to the API and returns the WebResponse:
Function GenerateCutlist(availableStock As String, desiredPieces As String, kerf As String) As WebResponse
If (Len(availableStock) And Len(desiredPieces)) Then
Dim CutClient As New WebClient
CutClient.BaseUrl = "http://cutlist.dotordotdot.com/json/"
' Create a WebRequest for getting CutList information
Dim CutListRequest As New WebRequest
CutListRequest.Resource = "generate.cutlist.1d"
CutListRequest.Method = WebMethod.HttpPost
' Set the request format
' -> Sets content-type and accept headers and parses response
CutListRequest.Format = WebFormat.Json
CutListRequest.ResponseFormat = WebFormat.Json
' Replace {format} segment
CutListRequest.AddUrlSegment "format", "json"
' Add querystring to the request
CutListRequest.AddQuerystringParam "apiKey", "00000000-0000-0000-0000-000000000000"
CutListRequest.AddQuerystringParam "availableStock", availableStock
CutListRequest.AddQuerystringParam "desiredPieces", desiredPieces
CutListRequest.AddQuerystringParam "kerf", "" & kerf & ""
CutListRequest.AddQuerystringParam "algorithm", "legacy"
CutListRequest.AddQuerystringParam "lengthUnit", "inches"
Dim Response As WebResponse
Set Response = CutClient.Execute(CutListRequest)
Set GenerateCutlist = Response
End If
End Function
The response is then output to the Required Matierals list by the ResponseOutput function:
Function ResponseOutput(Response As WebResponse, ws As Worksheet, lastRow As Long) As Long
'This clears the Required Material table (currently hardcoded to clear 96 rows)
'Only occurs on first run
If lastRow = 0 Then
ws.Range("N4:P100").Clear
End If
'Set the output row and column for the first "Required Parts" cell (Currently N4)
Dim OutputColumn As Integer
OutputColumn = 14
Dim OutputRow As Integer
If lastRow = 0 Then
OutputRow = 4
Else
OutputRow = lastRow
End If
For Each board In Response.Data("availableStock")
If board("quantityConsumed") + 0 > 0 Then
'Outputs board name (SKU)
ws.Cells(OutputRow, OutputColumn) = board("name")
'Get price for the SKU from available material table
ws.Cells(OutputRow, OutputColumn + 1) = ws.Cells(ws.Range("A:A").Find(board("name")).Row, 5)
'Outputs quantity consumed (QTY)
ws.Cells(OutputRow, OutputColumn + 2) = board("quantityConsumed") + 0
OutputRow = OutputRow + 1
End If
Next board
ResponseOutput = OutputRow
End Function
With a bit of effort, this should be enough information for you to integrate Jonathan Overholt's cutlist API into your own Excel projects.
Thanks for taking a look! Please contact me with questions or suggestions: [email protected]