feat: implement auto-discard feature for excess stock management
This commit is contained in:
@@ -765,6 +765,92 @@ function O.autoCompost()
|
|||||||
return didWork
|
return didWork
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------
|
||||||
|
-- Auto-discard excess stock
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
function O.discardExcess()
|
||||||
|
if #cfg.TRASH_DROPPERS == 0 then return false end
|
||||||
|
|
||||||
|
local catalogue = cache.catalogue
|
||||||
|
local didWork = false
|
||||||
|
|
||||||
|
-- Build a flat list of dropper handles + free capacity
|
||||||
|
local droppers = {}
|
||||||
|
for _, dName in ipairs(cfg.TRASH_DROPPERS) do
|
||||||
|
local d = O.wrapCached(dName)
|
||||||
|
if d then
|
||||||
|
local used = 0
|
||||||
|
local contents = d.list()
|
||||||
|
if contents then
|
||||||
|
for _, item in pairs(contents) do used = used + item.count end
|
||||||
|
end
|
||||||
|
local free = (d.size() * 64) - used
|
||||||
|
if free > 0 then
|
||||||
|
table.insert(droppers, { name = dName, handle = d, free = free })
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #droppers == 0 then return false end
|
||||||
|
|
||||||
|
-- Round-robin index across droppers
|
||||||
|
local dIdx = 1
|
||||||
|
|
||||||
|
for itemName, maxCount in pairs(cfg.STOCK_LIMITS) do
|
||||||
|
if catalogue[itemName] then
|
||||||
|
local totalInStorage = 0
|
||||||
|
for _, src in ipairs(catalogue[itemName]) do
|
||||||
|
totalInStorage = totalInStorage + src.total
|
||||||
|
end
|
||||||
|
|
||||||
|
local excess = totalInStorage - maxCount
|
||||||
|
if excess > 0 then
|
||||||
|
log.info("DISCARD", "%s: %d in stock, limit %d, discarding %d",
|
||||||
|
itemName, totalInStorage, maxCount, excess)
|
||||||
|
local discarded = 0
|
||||||
|
local srcSnapshot = { table.unpack(catalogue[itemName]) }
|
||||||
|
for _, source in ipairs(srcSnapshot) do
|
||||||
|
if discarded >= excess then break end
|
||||||
|
if source.total > 0 then
|
||||||
|
local chest = O.wrapCached(source.chest)
|
||||||
|
if chest then
|
||||||
|
for slot, slotItem in pairs(chest.list()) do
|
||||||
|
if slotItem.name == itemName then
|
||||||
|
-- Find a dropper with free space (round-robin)
|
||||||
|
local startIdx = dIdx
|
||||||
|
local dropper = nil
|
||||||
|
repeat
|
||||||
|
if droppers[dIdx].free > 0 then
|
||||||
|
dropper = droppers[dIdx]
|
||||||
|
end
|
||||||
|
dIdx = (dIdx % #droppers) + 1
|
||||||
|
until dropper or dIdx == startIdx
|
||||||
|
if not dropper then break end -- all droppers full
|
||||||
|
|
||||||
|
local batch = math.min(slotItem.count, excess - discarded, dropper.free)
|
||||||
|
local n = chest.pushItems(dropper.name, slot, batch)
|
||||||
|
if n and n > 0 then
|
||||||
|
state.adjustCache(itemName, source.chest, -n)
|
||||||
|
dropper.free = dropper.free - n
|
||||||
|
discarded = discarded + n
|
||||||
|
didWork = true
|
||||||
|
end
|
||||||
|
if discarded >= excess then break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if discarded > 0 then
|
||||||
|
log.info("DISCARD", "Discarded %s x%d", itemName, discarded)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return didWork
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
-- Low-stock alert checker
|
-- Low-stock alert checker
|
||||||
-------------------------------------------------
|
-------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user