<%
' Get all active printers
Dim strSQL, rs, printerid, printerwindowsname, printercsfname, ipaddress, machinenumber, modelnumber, machineid, vendor
Dim printerData, zabbixConnected, pingStatus, suppliesJSON
Dim lowSuppliesFound
lowSuppliesFound = False
strSQL = "SELECT printers.printerid, printers.printerwindowsname, printers.printercsfname, printers.ipaddress, " &_
"machines.machinenumber, machines.machineid, models.modelnumber, machines.alias, vendors.vendor " &_
"FROM printers " &_
"INNER JOIN models ON printers.modelid = models.modelnumberid " &_
"INNER JOIN machines ON printers.machineid = machines.machineid " &_
"INNER JOIN vendors ON models.vendorid = vendors.vendorid " &_
"WHERE printers.isactive = 1 AND printers.ipaddress IS NOT NULL AND printers.ipaddress != '' " &_
"ORDER BY machines.machinenumber ASC"
set rs = objconn.Execute(strSQL)
While Not rs.EOF
printerid = rs("printerid")
printerwindowsname = rs("printerwindowsname")
printercsfname = rs("printercsfname")
ipaddress = rs("ipaddress")
modelnumber = rs("modelnumber")
machineid = rs("machineid")
vendor = rs("vendor")
' Use alias if available, otherwise machinenumber
If NOT IsNull(rs("alias")) AND rs("alias") <> "" Then
machinenumber = rs("alias")
Else
machinenumber = rs("machinenumber")
End If
' Get cached Zabbix data for this printer (all supplies including maintenance)
printerData = GetAllPrinterSuppliesCached(ipaddress)
If Not IsEmpty(printerData) And IsArray(printerData) Then
zabbixConnected = printerData(0)
pingStatus = printerData(1)
suppliesJSON = printerData(2)
' Parse supplies JSON to find items below 20%
If zabbixConnected = "1" And suppliesJSON <> "" And InStr(suppliesJSON, """result"":[") > 0 Then
' Check if result array is not empty
If InStr(suppliesJSON, """result"":[]") = 0 Then
' Declare all variables at the top to avoid redeclaration errors
Dim itemStart, itemEnd, currentPos, itemBlock
Dim itemName, itemValue, itemStatus, itemState
Dim namePos, nameStart, nameEnd
Dim valuePos, valueStart, valueEnd
Dim statusPos, statusStart, statusEnd
Dim statePos, stateStart, stateEnd
Dim baseName
Dim numericValue
Dim statusIcon, statusColor, statusText
Dim partNumber, lookupName, i
' First pass: Build lookup of part numbers (type:info items)
' Use Dictionary object for more reliable storage
Dim partNumbers
Set partNumbers = Server.CreateObject("Scripting.Dictionary")
Dim debugPartNumbers, debugAllItems, debugItemCount
debugPartNumbers = ""
debugAllItems = ""
debugItemCount = 0
currentPos = InStr(suppliesJSON, """result"":[") + 11
' Scan for part number items (containing "Part Number" in name)
Do While currentPos > 11 And currentPos < Len(suppliesJSON)
itemStart = InStr(currentPos, suppliesJSON, "{""itemid"":")
If itemStart = 0 Then Exit Do
itemEnd = InStr(itemStart, suppliesJSON, "},{")
If itemEnd = 0 Then itemEnd = InStr(itemStart, suppliesJSON, "}]")
If itemEnd = 0 Then Exit Do
itemBlock = Mid(suppliesJSON, itemStart, itemEnd - itemStart + 1)
' Extract name
namePos = InStr(itemBlock, """name"":""")
If namePos > 0 Then
nameStart = namePos + 8
nameEnd = InStr(nameStart, itemBlock, """")
itemName = Mid(itemBlock, nameStart, nameEnd - nameStart)
Else
itemName = ""
End If
' DEBUG: Track all items scanned
debugItemCount = debugItemCount + 1
If debugItemCount <= 10 Then
debugAllItems = debugAllItems & itemName & " | "
End If
' If this is a part number item, store it
' Look for various part number patterns (case-insensitive)
If InStr(1, itemName, "Part Number", 1) > 0 Or InStr(1, itemName, "Part number", 1) > 0 Or InStr(1, itemName, "OEM", 1) > 0 Or InStr(1, itemName, "SKU", 1) > 0 Then
valuePos = InStr(itemBlock, """lastvalue"":""")
If valuePos > 0 Then
valueStart = valuePos + 13
valueEnd = InStr(valueStart, itemBlock, """")
itemValue = Mid(itemBlock, valueStart, valueEnd - valueStart)
' Store in dictionary with full item name as key (e.g., "Black Toner Part Number")
If Not partNumbers.Exists(itemName) Then
partNumbers.Add itemName, itemValue
debugPartNumbers = debugPartNumbers & "[" & itemName & "=" & itemValue & "] "
End If
End If
End If
currentPos = itemEnd + 1
Loop
' Debug disabled - uncomment to show part number matching debug info
' Response.Write("
")
' Second pass: Find level items below 20%
currentPos = InStr(suppliesJSON, """result"":[") + 11
Do While currentPos > 11 And currentPos < Len(suppliesJSON)
' Find next item
itemStart = InStr(currentPos, suppliesJSON, "{""itemid"":")
If itemStart = 0 Then Exit Do
' Find end of this item
itemEnd = InStr(itemStart, suppliesJSON, "},{")
If itemEnd = 0 Then
' Last item in array
itemEnd = InStr(itemStart, suppliesJSON, "}]")
End If
If itemEnd = 0 Then Exit Do
itemBlock = Mid(suppliesJSON, itemStart, itemEnd - itemStart + 1)
' Extract item name - "name":" is 8 characters
namePos = InStr(itemBlock, """name"":""")
If namePos > 0 Then
nameStart = namePos + 8
nameEnd = InStr(nameStart, itemBlock, """")
itemName = Mid(itemBlock, nameStart, nameEnd - nameStart)
Else
itemName = "Unknown"
End If
' Extract lastvalue - "lastvalue":" is 13 characters
valuePos = InStr(itemBlock, """lastvalue"":""")
If valuePos > 0 Then
valueStart = valuePos + 13
valueEnd = InStr(valueStart, itemBlock, """")
itemValue = Mid(itemBlock, valueStart, valueEnd - valueStart)
Else
itemValue = "0"
End If
' Extract status (0 = enabled, 1 = disabled) - "status":" is 10 characters
statusPos = InStr(itemBlock, """status"":""")
If statusPos > 0 Then
statusStart = statusPos + 10
statusEnd = InStr(statusStart, itemBlock, """")
itemStatus = Mid(itemBlock, statusStart, statusEnd - statusStart)
Else
itemStatus = "0"
End If
' Extract state (0 = normal, 1 = not supported) - "state":" is 9 characters
statePos = InStr(itemBlock, """state"":""")
If statePos > 0 Then
stateStart = statePos + 9
stateEnd = InStr(stateStart, itemBlock, """")
itemState = Mid(itemBlock, stateStart, stateEnd - stateStart)
Else
itemState = "0"
End If
' Convert value to number and check if below 20%
On Error Resume Next
numericValue = CDbl(itemValue)
On Error Goto 0
' Filter: Only show actual supply level items (must have "Level" in name)
Dim isSupplyItem
isSupplyItem = False
If InStr(1, itemName, "Level", 1) > 0 Then
' Exclude non-supply items
If InStr(1, itemName, "Part Number", 1) = 0 And _
InStr(1, itemName, "ICMP", 1) = 0 And _
InStr(1, itemName, "ping", 1) = 0 And _
InStr(1, itemName, "loss", 1) = 0 And _
InStr(1, itemName, "response", 1) = 0 And _
InStr(1, itemName, "Hostname", 1) = 0 And _
InStr(1, itemName, "Model", 1) = 0 And _
InStr(1, itemName, "Serial", 1) = 0 And _
InStr(1, itemName, "Location", 1) = 0 And _
InStr(1, itemName, "Firmware", 1) = 0 And _
InStr(1, itemName, "Current", 1) = 0 And _
InStr(1, itemName, " Max", 1) = 0 Then
isSupplyItem = True
End If
End If
' Only show items that are supply items, below 20%, enabled, and normal state
If isSupplyItem And numericValue < 20 And numericValue >= 0 And itemStatus = "0" And itemState = "0" Then
lowSuppliesFound = True
' Determine status indicator
If numericValue <= 5 Then
statusIcon = "zmdi-alert-circle"
statusColor = "#ff0000"
statusText = "Critical"
ElseIf numericValue <= 10 Then
statusIcon = "zmdi-alert-triangle"
statusColor = "#ff6600"
statusText = "Very Low"
Else
statusIcon = "zmdi-info"
statusColor = "#ffaa00"
statusText = "Low"
End If
' Look up part number for this item
partNumber = "-"
If partNumbers.Count > 0 Then
' Extract base name for lookup - remove " Level" suffix
lookupName = Replace(itemName, " Level", "")
lookupName = Trim(lookupName)
' Comprehensive matching strategy for all template versions
Dim partKeyName, tryName, partKey
Dim foundMatch
foundMatch = False
' Strategy 1: EXACT match - NEW template format (preferred)
' "Black Toner Level" → "Black Toner Part Number"
' "Cyan Ink Level" → "Cyan Ink Part Number"
' "Black Drum Level" → "Black Drum Part Number"
partKeyName = lookupName & " Part Number"
If partNumbers.Exists(partKeyName) Then
partNumber = partNumbers(partKeyName)
foundMatch = True
End If
' Strategy 2: Add " Cartridge" - OLD Xerox template format
' "Black Drum Level" → "Black Drum Cartridge Part Number"
' "Black Toner Level" → "Black Toner Cartridge Part Number"
If Not foundMatch Then
tryName = lookupName & " Cartridge Part Number"
If partNumbers.Exists(tryName) Then
partNumber = partNumbers(tryName)
foundMatch = True
End If
End If
' Strategy 3: Replace supply type with "Cartridge" - OLD HP template format
' "Black Toner Level" → "Black Cartridge Part Number"
' "Cyan Ink Level" → "Cyan Cartridge Part Number"
If Not foundMatch Then
' Replace common supply types with "Cartridge"
If InStr(1, lookupName, "Toner", 1) > 0 Then
tryName = Replace(lookupName, "Toner", "Cartridge", 1, -1, 1) & " Part Number"
ElseIf InStr(1, lookupName, "Ink", 1) > 0 Then
tryName = Replace(lookupName, "Ink", "Cartridge", 1, -1, 1) & " Part Number"
ElseIf InStr(1, lookupName, "Drum", 1) > 0 Then
tryName = Replace(lookupName, "Drum", "Cartridge", 1, -1, 1) & " Part Number"
Else
tryName = ""
End If
If tryName <> "" And partNumbers.Exists(tryName) Then
partNumber = partNumbers(tryName)
foundMatch = True
End If
End If
' Strategy 4: Check for "Standard MIB" suffix variation
' "Maintenance Kit Level" → "Maintenance Kit Part Number (Standard MIB)"
If Not foundMatch Then
tryName = lookupName & " Part Number (Standard MIB)"
If partNumbers.Exists(tryName) Then
partNumber = partNumbers(tryName)
foundMatch = True
End If
End If
' Strategy 5: Intelligent fuzzy match by type and color
If Not foundMatch Then
' Extract primary identifier (first significant word)
Dim primaryWord, supplyType
primaryWord = ""
supplyType = ""
' Determine supply type
If InStr(1, lookupName, "Toner", 1) > 0 Then
supplyType = "Toner"
ElseIf InStr(1, lookupName, "Ink", 1) > 0 Then
supplyType = "Ink"
ElseIf InStr(1, lookupName, "Drum", 1) > 0 Then
supplyType = "Drum"
ElseIf InStr(1, lookupName, "Waste", 1) > 0 Then
supplyType = "Waste"
ElseIf InStr(1, lookupName, "Fuser", 1) > 0 Then
supplyType = "Fuser"
ElseIf InStr(1, lookupName, "Maintenance", 1) > 0 Then
supplyType = "Maintenance"
End If
' Extract color/identifier (first word before supply type)
If supplyType <> "" Then
Dim colorPos
colorPos = InStr(1, lookupName, supplyType, 1)
If colorPos > 1 Then
primaryWord = Trim(Left(lookupName, colorPos - 1))
End If
End If
' Search all keys for matching type and color
For Each partKey In partNumbers.Keys
If InStr(1, partKey, "Part Number", 1) > 0 Then
' Must match supply type
Dim typeMatches
typeMatches = False
If supplyType <> "" Then
typeMatches = (InStr(1, partKey, supplyType, 1) > 0) Or (InStr(1, partKey, "Cartridge", 1) > 0)
Else
' For items without obvious type, just look for any match
typeMatches = True
End If
' Must match color/identifier if present
Dim colorMatches
colorMatches = True
If primaryWord <> "" Then
colorMatches = (InStr(1, partKey, primaryWord, 1) > 0)
End If
If typeMatches And colorMatches Then
partNumber = partNumbers(partKey)
foundMatch = True
Exit For
End If
End If
Next
End If
End If
Response.Write("