<% ' ============================================================================ ' FUNCTION: SafeGetZabbixData ' PURPOSE: Safely call Zabbix function with error handling ' ============================================================================ Function SafeGetZabbixData(ipaddress) On Error Resume Next Dim result result = GetAllPrinterSuppliesCached(ipaddress) If Err.Number <> 0 Then result = Empty Err.Clear End If On Error Goto 0 SafeGetZabbixData = result End Function theme = Request.Cookies("theme") IF theme = "" THEN theme="bg-theme1" END IF ' ============================================================================ ' FUNCTION: GetActualPartNumber ' PURPOSE: Replace generic "Genuine Xerox(R) Toner" with actual part number based on model ' ============================================================================ Function GetActualPartNumber(partNumber, printerModel, colorName) Dim cleanPartNumber, cleanUpper cleanPartNumber = Trim(partNumber) cleanUpper = UCase(cleanPartNumber) ' Check if it contains generic Xerox text (handle various spacing) ' "Genuine Xerox(R) Toner" or "Genuine Xerox (R) Toner" or variations If InStr(1, cleanUpper, "GENUINE XEROX", 1) = 0 Then ' Not a generic Xerox part number, return as-is GetActualPartNumber = cleanPartNumber Exit Function End If ' Map generic Xerox part numbers to actual part numbers based on model Dim modelUpper, colorUpper, actualPN modelUpper = UCase(Trim(printerModel)) colorUpper = UCase(Trim(colorName)) actualPN = cleanPartNumber ' default to original ' Xerox VersaLink B400/B405 Monochrome If InStr(modelUpper, "VERSALINK B4") > 0 Or InStr(modelUpper, " B400") > 0 Or InStr(modelUpper, " B405") > 0 Then actualPN = "106R03581" ' Standard capacity ' Xerox VersaLink B600/B605/B610/B615 Monochrome ElseIf InStr(modelUpper, "VERSALINK B6") > 0 Or InStr(modelUpper, " B600") > 0 Or InStr(modelUpper, " B605") > 0 Or InStr(modelUpper, " B610") > 0 Or InStr(modelUpper, " B615") > 0 Then actualPN = "106R03940" ' Standard capacity ' Xerox VersaLink B7025/B7030/B7035 Monochrome (WorkCentre 7800 series) ElseIf InStr(modelUpper, "B7025") > 0 Or InStr(modelUpper, "B7030") > 0 Or InStr(modelUpper, "B7035") > 0 Or InStr(modelUpper, "7800") > 0 Then actualPN = "006R01756" ' Xerox VersaLink B7125/B7130/B7135 Monochrome ElseIf InStr(modelUpper, "B7125") > 0 Or InStr(modelUpper, "B7130") > 0 Or InStr(modelUpper, "B7135") > 0 Then actualPN = "006R01818" ' High capacity End If GetActualPartNumber = actualPN End Function ' ============================================================================ ' FUNCTION: GetMarketingName ' PURPOSE: Convert OEM part numbers to marketing names for easier supply closet matching ' ============================================================================ Function GetMarketingName(oemPartNumber) Dim oem, marketing, hpPos, pnPos ' Extract just the part number from full descriptions ' Examples: ' "Black Cartridge HP W2020A" → "W2020A" ' "Black Toner Cartridge, PN 106R03536" → "106R03536" ' "W2020A" → "W2020A" oem = UCase(Trim(oemPartNumber)) ' Check for "HP " prefix (most HP printers) hpPos = InStr(oem, "HP ") If hpPos > 0 Then oem = Trim(Mid(oem, hpPos + 3)) ' Remove anything in parentheses at the end If InStr(oem, "(") > 0 Then oem = Trim(Left(oem, InStr(oem, "(") - 1)) End If End If ' Check for "PN " prefix (Xerox and some others) pnPos = InStr(oem, "PN ") If pnPos > 0 Then oem = Trim(Mid(oem, pnPos + 3)) End If ' Remove trailing parentheses content if any If InStr(oem, ")") > 0 Then oem = Trim(Left(oem, InStr(oem, "(") - 1)) End If ' HP M454dw / M454dn / M479fdw (414A/414X series) If oem = "W2020A" Or oem = "W2020X" Then marketing = "414A/414X Black" ElseIf oem = "W2021A" Or oem = "W2021X" Then marketing = "414A/414X Cyan" ElseIf oem = "W2022A" Or oem = "W2022X" Then marketing = "414A/414X Yellow" ElseIf oem = "W2023A" Or oem = "W2023X" Then marketing = "414A/414X Magenta" ' HP M254dw / M255dw (202A/202X series) ElseIf oem = "CF500A" Or oem = "CF500X" Then marketing = "202A/202X Black" ElseIf oem = "CF501A" Or oem = "CF501X" Then marketing = "202A/202X Cyan" ElseIf oem = "CF502A" Or oem = "CF502X" Then marketing = "202A/202X Yellow" ElseIf oem = "CF503A" Or oem = "CF503X" Then marketing = "202A/202X Magenta" ' HP M251nw / M252dw (201A/201X series) ElseIf oem = "CF400A" Or oem = "CF400X" Then marketing = "201A/201X Black" ElseIf oem = "CF401A" Or oem = "CF401X" Then marketing = "201A/201X Cyan" ElseIf oem = "CF402A" Or oem = "CF402X" Then marketing = "201A/201X Yellow" ElseIf oem = "CF403A" Or oem = "CF403X" Then marketing = "201A/201X Magenta" ' HP LaserJet 200 color M251nw (131A/131X series) ElseIf oem = "CF210A" Or oem = "CF210X" Then marketing = "131A/131X Black" ElseIf oem = "CF211A" Then marketing = "131A Cyan" ElseIf oem = "CF212A" Then marketing = "131A Yellow" ElseIf oem = "CF213A" Then marketing = "131A Magenta" ' HP M404n / M406 (58A/58X series) ElseIf oem = "CF258A" Or oem = "CF258X" Or oem = "CF258XC" Then marketing = "58A/58X Black" ' HP M607 / M608 / M609 (37A/37X series) ElseIf oem = "CF237A" Or oem = "CF237X" Then marketing = "37A/37X Black" ' HP M506 / M607 (87A/87X series) ElseIf oem = "CF287A" Or oem = "CF287X" Then marketing = "87A/87X Black" ' HP M602 (90A/90X series) ElseIf oem = "CE390A" Or oem = "CE390X" Then marketing = "90A/90X Black" ' HP P3015dn (55A/55X series) ElseIf oem = "CE255A" Or oem = "CE255X" Then marketing = "55A/55X Black" ' HP LaserJet 4250tn (42A/42X series) ElseIf oem = "Q5942A" Or oem = "Q5942X" Then marketing = "42A/42X Black" ' HP LaserJet Pro 4001n (147A/147X series) ElseIf oem = "W1470A" Or oem = "W1470X" Or oem = "W1480X" Then marketing = "147A/147X Black" ' HP M454 / M479 High Capacity (120X series) ElseIf oem = "W1020X" Or oem = "W1020XC" Then marketing = "120X Black" ' HP Imaging Drums ElseIf oem = "CF234A" Then marketing = "34A Drum" ElseIf oem = "CF219A" Then marketing = "19A Drum" ElseIf oem = "W2030A" Or oem = "W2030X" Then marketing = "415A/415X Drum" ' HP Maintenance Kits ElseIf oem = "CF254A" Then marketing = "54A Maintenance Kit" ElseIf oem = "CF247A" Then marketing = "47A Maintenance Kit" ' HP 730 DesignJet Inks (T1700/T1600 series) ElseIf oem = "P2V68A" Then marketing = "730 Cyan Ink" ElseIf oem = "P2V69A" Then marketing = "730 Magenta Ink" ElseIf oem = "P2V70A" Then marketing = "730 Yellow Ink" ElseIf oem = "P2V71A" Then marketing = "730 Matte Black Ink" ElseIf oem = "P2V72A" Then marketing = "730 Gray Ink" ElseIf oem = "P2V73A" Then marketing = "730 Photo Black Ink" ' Xerox VersaLink B400/B405 Monochrome ElseIf oem = "106R03581" Then marketing = "Xerox Black Toner (Standard)" ElseIf oem = "106R03583" Then marketing = "Xerox Black Toner (High Cap)" ElseIf oem = "106R03585" Then marketing = "Xerox Black Toner (Extra High Cap)" ' Xerox VersaLink B600/B610/B615 Monochrome ElseIf oem = "106R03940" Then marketing = "Xerox Black Toner (Standard)" ElseIf oem = "106R03942" Then marketing = "Xerox Black Toner (High Cap)" ElseIf oem = "106R03944" Then marketing = "Xerox Black Toner (Extra High Cap)" ' Xerox VersaLink B7025/B7030/B7035 Monochrome (WorkCentre 7800 series) ElseIf oem = "006R01756" Then marketing = "Xerox Black Toner" ' Xerox VersaLink B7125/B7130/B7135 Monochrome ElseIf oem = "006R01817" Then marketing = "Xerox Black Toner (Standard)" ElseIf oem = "006R01818" Then marketing = "Xerox Black Toner (High Capacity)" ElseIf oem = "006R01819" Then marketing = "Xerox Black Toner (DMO)" ' Xerox VersaLink C7000 series ElseIf oem = "106R03536" Then marketing = "Xerox Black Toner" ElseIf oem = "106R03537" Then marketing = "Xerox Yellow Toner" ElseIf oem = "106R03538" Then marketing = "Xerox Cyan Toner" ElseIf oem = "106R03539" Then marketing = "Xerox Magenta Toner" ' Xerox WorkCentre 7800 series ElseIf oem = "006R01509" Then marketing = "Xerox Black Toner" ElseIf oem = "006R01510" Then marketing = "Xerox Yellow Toner" ElseIf oem = "006R01511" Then marketing = "Xerox Magenta Toner" ElseIf oem = "006R01512" Then marketing = "Xerox Cyan Toner" ' Xerox AltaLink C8030/C8035 series ElseIf oem = "006R01820" Then marketing = "Xerox Black Toner" ElseIf oem = "006R01821" Then marketing = "Xerox Cyan Toner" ElseIf oem = "006R01822" Then marketing = "Xerox Magenta Toner" ElseIf oem = "006R01823" Then marketing = "Xerox Yellow Toner" ' Xerox WorkCentre 7970 series ElseIf oem = "006R01742" Then marketing = "Xerox Black Toner" ElseIf oem = "006R01743" Then marketing = "Xerox Cyan Toner" ElseIf oem = "006R01744" Then marketing = "Xerox Magenta Toner" ElseIf oem = "006R01745" Then marketing = "Xerox Yellow Toner" ' Xerox Phaser 4600/4620 series ElseIf oem = "006R01817" Then marketing = "Xerox Black Toner" ' Xerox (legacy - keeping for compatibility) ElseIf oem = "006R01697" Then marketing = "Xerox Black Toner" ElseIf oem = "006R01698" Then marketing = "Xerox Cyan Toner" ElseIf oem = "006R01699" Then marketing = "Xerox Yellow Toner" ElseIf oem = "006R01700" Then marketing = "Xerox Magenta Toner" Else marketing = "" ' No mapping found - will display OEM number only End If GetMarketingName = marketing End Function %>

##### Supplies Alert Report

Monitors: Toner/Ink ≤5%, Drums ≤5%, Maintenance Kits ≤5%, Waste ≥95% (Xerox EC series: ≤5% inverted)

Printer | Location | Model | Level | Part Number
--- | --- | --- | --- | ---
<% ' Declare all variables at top level Dim strSQL, rs, printerid, printerwindowsname, printercsfname, ipaddress, machinenumber, modelnumber, machineid, vendor Dim printerData, zabbixConnected, pingStatus, suppliesJSON Dim lowSuppliesFound 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, numericValue Dim statusIcon, statusColor, statusText Dim partNumber, lookupName Dim partNumbers Dim debugPartNumbers, debugAllItems, debugItemCount Dim isSupplyItem, isWasteItem, showItem Dim marketingName, displayPartNumber Dim partKeyName, tryName, partKey, foundMatch Dim primaryWord, supplyType, colorPos Dim typeMatches, colorMatches Dim urgencyScore, alertItem, alertItems(1000), alertCount, i, j, tempAlert, k, outputItem Dim isXeroxPrinter lowSuppliesFound = False alertCount = 0 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") ' Detect if this is a Xerox EC series printer (EC8036, etc.) for vendor-specific logic ' These enterprise models report waste cartridges inverted from standard behavior isXeroxPrinter = (InStr(1, vendor, "Xerox", 1) > 0 And InStr(1, modelnumber, "EC", 1) > 0) ' 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 = SafeGetZabbixData(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 ' First pass: Build lookup of part numbers (type:info items) ' Use Dictionary object for more reliable storage Set partNumbers = Server.CreateObject("Scripting.Dictionary") 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("
") ' 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("
") ' 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) 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 ' Detect if this is a waste cartridge (works backwards - high % is bad) isWasteItem = (InStr(1, itemName, "Waste", 1) > 0) ' Check if item should be shown based on type showItem = False If isSupplyItem And itemStatus = "0" And itemState = "0" Then If isWasteItem Then ' Waste cartridge logic - MODEL SPECIFIC! ' Standard (HP, etc.): 0% = empty/ok, 100% = full/bad (alert when >=95%) ' Xerox EC series (EC8036, etc.): 0% = full/bad, 100% = empty/ok (INVERTED - alert when <=5%) If isXeroxPrinter Then ' Xerox EC series waste: alert when at or BELOW 5% (inverted - low % means full) If numericValue <= 5 And numericValue >= 0 Then showItem = True End If Else ' Standard waste: alert when at or ABOVE 95% (nearly full) If numericValue >= 95 And numericValue <= 100 Then showItem = True End If End If Else ' Regular supplies: alert when at or below 5% (running low) If numericValue <= 5 And numericValue >= 0 Then showItem = True End If End If End If If showItem Then lowSuppliesFound = True ' Determine status indicator If isWasteItem Then If isXeroxPrinter Then ' Xerox EC series waste: INVERTED - low % = full/bad If numericValue <= 5 Then statusIcon = "zmdi-alert-circle" statusColor = "#ff0000" statusText = "Critical - Nearly Full" ElseIf numericValue <= 10 Then statusIcon = "zmdi-alert-triangle" statusColor = "#ff6600" statusText = "Very High" Else statusIcon = "zmdi-info" statusColor = "#ffaa00" statusText = "High" End If Else ' Standard waste (HP, etc.): high % = full/bad If numericValue >= 95 Then statusIcon = "zmdi-alert-circle" statusColor = "#ff0000" statusText = "Critical - Nearly Full" ElseIf numericValue >= 90 Then statusIcon = "zmdi-alert-triangle" statusColor = "#ff6600" statusText = "Very High" Else statusIcon = "zmdi-info" statusColor = "#ffaa00" statusText = "High" End If End If Else ' Regular supply status (low % = bad) ' 0% = Critical (red), 1-5% = Warning (orange) If numericValue = 0 Then statusIcon = "zmdi-alert-circle" statusColor = "#ff0000" statusText = "Critical" Else statusIcon = "zmdi-alert-triangle" statusColor = "#ff6600" statusText = "Warning" End If 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 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) 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 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 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 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 ' Replace generic Xerox part numbers with actual model-specific part numbers partNumber = GetActualPartNumber(partNumber, modelnumber, itemName) ' Get marketing name for this part number marketingName = GetMarketingName(partNumber) If marketingName <> "" Then ' Show marketing name prominently with OEM number in smaller text displayPartNumber = "" & Server.HTMLEncode(marketingName) & "
" & Server.HTMLEncode(partNumber) & "" Else ' No mapping found, just show OEM number displayPartNumber = Server.HTMLEncode(partNumber) End If ' Calculate urgency score for sorting ' For regular supplies: lower % = higher urgency (5% = 95 urgency) ' For standard waste: higher % = higher urgency (95% = 95 urgency) ' For Xerox EC series waste: INVERTED - lower % = higher urgency (5% = 95 urgency) If isWasteItem Then If isXeroxPrinter Then ' Xerox EC series waste: inverted - low % is bad urgencyScore = 100 - numericValue Else ' Standard waste: high % is bad urgencyScore = numericValue End If Else ' Regular supplies: low % is bad urgencyScore = 100 - numericValue End If ' Store alert data for later sorting alertItem = Array( _ urgencyScore, _ vendor, _ printerid, _ printerwindowsname, _ machineid, _ machinenumber, _ modelnumber, _ numericValue, _ statusColor, _ displayPartNumber, _ itemName _ ) alertItems(alertCount) = alertItem alertCount = alertCount + 1 End If ' Move to next item currentPos = itemEnd + 1 Loop End If End If End If rs.MoveNext Wend ' Sort alerts by urgency (highest urgency first = most critical) ' Simple bubble sort with error handling On Error Resume Next If alertCount > 1 Then For i = 0 To alertCount - 2 For j = 0 To alertCount - i - 2 ' alertItems(j)(0) is the urgency score If Not IsEmpty(alertItems(j)) And Not IsEmpty(alertItems(j + 1)) Then If CDbl(alertItems(j)(0)) < CDbl(alertItems(j + 1)(0)) Then ' Swap items tempAlert = alertItems(j) alertItems(j) = alertItems(j + 1) alertItems(j + 1) = tempAlert End If End If Next Next End If ' Output sorted alerts If alertCount > 0 Then lowSuppliesFound = True For k = 0 To alertCount - 1 If Not IsEmpty(alertItems(k)) And IsArray(alertItems(k)) Then outputItem = alertItems(k) ' Array indices: 0=urgencyScore, 1=vendor, 2=printerid, 3=printerwindowsname, ' 4=machineid, 5=machinenumber, 6=modelnumber, 7=numericValue, ' 8=statusColor, 9=displayPartNumber, 10=itemName Response.Write("
") Response.Write("
") Response.Write("
") Response.Write("
") Response.Write("
") Response.Write("
") Response.Write("
" & Server.HTMLEncode(outputItem(3)) & " | " & Server.HTMLEncode(outputItem(5)) & " | " & Server.HTMLEncode(outputItem(6)) & " | " & Round(CDbl(outputItem(7)), 1) & "% | " & outputItem(9) & "
") End If Next End If On Error Goto 0 If Not lowSuppliesFound Then Response.Write("
") Response.Write(" ") Response.Write("No supply issues found - All printers have adequate supplies") Response.Write("
") End If objConn.Close %>