<% theme = Request.Cookies("theme") IF theme = "" THEN theme="bg-theme1" END IF %>
  Low Supplies Report (<20%)

Monitors: Toner/Ink Cartridges, Imaging Drums, Maintenance Kits, Waste Cartridges, Transfer Belts, Fusers

<% ' 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("") Response.Write("") Response.Write("") Response.Write("") Response.Write("") Response.Write("") Response.Write("") End If ' Move to next item currentPos = itemEnd + 1 Loop End If End If End If rs.MoveNext Wend If Not lowSuppliesFound Then Response.Write("") End If objConn.Close %>
Printer Location Model Level Part Number
") ' Response.Write("DEBUG (" & ipaddress & "): Scanned " & debugItemCount & " items | ") ' Response.Write("First 10: " & Server.HTMLEncode(debugAllItems) & "
") ' If debugPartNumbers <> "" Then ' Response.Write("Part Numbers Found: " & Server.HTMLEncode(debugPartNumbers)) ' Else ' Response.Write("No part numbers found!") ' End If ' Response.Write("
" & printerwindowsname & "" & machinenumber & "" & modelnumber & "" & Round(numericValue, 1) & "%" & Server.HTMLEncode(partNumber) & "
") Response.Write("
") Response.Write("No printers found with supplies below 20%") Response.Write("