--[[
|
版本: Version 1.0
|
创建日期: 2025-6-26
|
创建人: KUN
|
|
功能:
|
wms_wh Lua程序包整合了一些和【仓库】【库区】【货位】【巷道】这些仓库基础构成对象相关的操作
|
|
-- PICK_LOC 获取推荐货位
|
-- OperationCancel WCS调用取消作业
|
|
|
更改说明:
|
--]]
|
|
wms_base = require ("wms_base")
|
wms_cntr = require ("wms_container")
|
wms_cntr = require("wms_container")
|
wms_op = require("wms_operation")
|
wms_task = require("wms_task")
|
wms_wh = require("wms_wh")
|
|
local ams_base = {_version = "0.1.1"}
|
|
-- 内侧排定义
|
local InsideRows = {
|
[1] = {1, 4},
|
[2] = {5, 8},
|
}
|
|
-- 内外排映射
|
local innerOuterMap = {
|
[1] = 2, [4] = 3,
|
[5] = 6, [8] = 7,
|
}
|
|
-- 查询所有货位(缓存方式)
|
local function buildLocationCache(strLuaDEID, aisle)
|
local cache = {}
|
for row = 1, 8 do
|
cache[row] = {}
|
for layer = 1, 10 do
|
local cond = string.format("C_ENABLE='Y' AND N_AISLE=%d AND N_ROW=%d AND N_LAYER=%d", aisle, row, layer)
|
local nRet, strRetInfo = mobox.queryDataObjAttr2(strLuaDEID, "Location", cond, "N_COL ASC", 200,
|
"S_CODE", "N_COL", "N_ROW", "N_LAYER", "N_POS", "S_AREA_CODE", "N_CURRENT_NUM", "N_LOCK_STATE")
|
if nRet == 0 and strRetInfo then
|
local ok, queryInfo = pcall(json.decode, strRetInfo)
|
if ok and queryInfo.dataSet then
|
local locs = {}
|
for _, item in ipairs(queryInfo.dataSet) do
|
local loc = {}
|
for _, attr in ipairs(item.attrs or {}) do
|
loc[attr.attr] = tonumber(attr.value) or attr.value
|
end
|
table.insert(locs, loc)
|
end
|
cache[row][layer] = locs
|
end
|
end
|
end
|
end
|
return cache
|
end
|
|
local function isInnerLocUsable(cache, loc)
|
local outerRow = innerOuterMap[loc.N_ROW]
|
if not outerRow then return true end
|
local outerLocs = cache[outerRow] and cache[outerRow][loc.N_LAYER] or {}
|
for _, oLoc in ipairs(outerLocs) do
|
if oLoc.N_COL == loc.N_COL and (oLoc.N_CURRENT_NUM > 0 or oLoc.N_LOCK_STATE > 0) then
|
return false
|
end
|
end
|
return true
|
end
|
|
local function isOuterLocUsable(cache, loc)
|
local innerRow = nil
|
for k, v in pairs(innerOuterMap) do
|
if v == loc.N_ROW then
|
innerRow = k
|
break
|
end
|
end
|
if not innerRow then return true end
|
local innerLocs = cache[innerRow] and cache[innerRow][loc.N_LAYER] or {}
|
for _, iLoc in ipairs(innerLocs) do
|
if iLoc.N_COL == loc.N_COL and iLoc.N_LOCK_STATE > 0 then
|
return false
|
end
|
end
|
return true
|
end
|
|
local function pickAdjacentSameRow(locList, containerCount)
|
table.sort(locList, function(a, b) return a.N_COL < b.N_COL end)
|
for i = 1, #locList - (containerCount - 1) do
|
local continuous = true
|
for j = 1, containerCount - 1 do
|
if locList[i + j].N_COL ~= locList[i].N_COL + j then
|
continuous = false
|
break
|
end
|
end
|
if continuous then
|
local pair = {}
|
for k = 0, containerCount - 1 do
|
table.insert(pair, locList[i + k])
|
end
|
return pair
|
end
|
end
|
return nil
|
end
|
|
local function tryAssignFixedLayerOrder(cache, rows, containerCount, layerOrder, isInner, occupiedSet)
|
for _, layer in ipairs(layerOrder) do
|
for _, row in ipairs(rows) do
|
local locs = cache[row] and cache[row][layer] or {}
|
local filtered = {}
|
for _, loc in ipairs(locs) do
|
if loc.N_LOCK_STATE == 0 and loc.N_CURRENT_NUM == 0 and not occupiedSet[loc.S_CODE] then
|
if isInner and isInnerLocUsable(cache, loc) then
|
table.insert(filtered, loc)
|
elseif not isInner and isOuterLocUsable(cache, loc) then
|
table.insert(filtered, loc)
|
end
|
end
|
end
|
if containerCount >= 2 then
|
local pair = pickAdjacentSameRow(filtered, containerCount)
|
if pair then return pair end
|
end
|
if #filtered >= containerCount then
|
local res = {}
|
for i = 1, containerCount do
|
table.insert(res, filtered[i])
|
end
|
return res
|
end
|
end
|
end
|
return nil
|
end
|
|
local function Recommend(strLuaDEID, taskList)
|
local result = {}
|
local aisle = taskList[1].curPos
|
if not aisle then return false, "任务参数curPos无效" end
|
|
local innerRows = InsideRows[aisle]
|
if not innerRows then return false, "未定义巷道内侧排" end
|
|
local outerRows = {}
|
for r = 1, 8 do
|
local isInner = false
|
for _, v in ipairs(innerRows) do if v == r then isInner = true break end end
|
if not isInner then table.insert(outerRows, r) end
|
end
|
|
local occupiedSet = {}
|
local cache = buildLocationCache(strLuaDEID, aisle)
|
|
for _, task in ipairs(taskList) do
|
local cntr_code = task.containerCode
|
local nRet, cntr_obj = wms_cntr.GetInfo(strLuaDEID, cntr_code)
|
if nRet ~= 0 or cntr_obj == '' then return false, "料箱不存在: "..cntr_code end
|
|
local containerCount = cntr_obj.nContain or 1
|
local containerType = cntr_obj.ctd_code or ""
|
if containerType == "" then return false, "容器未定义类型: "..cntr_code end
|
|
local priLayers, secLayers = {}, {}
|
if containerType == "CTD-001" then
|
for l = 5, 10 do table.insert(priLayers, l) end
|
for l = 1, 4 do table.insert(secLayers, l) end
|
elseif containerType == "CTD-002" then
|
for l = 1, 4 do table.insert(priLayers, l) end
|
end
|
|
local locs = tryAssignFixedLayerOrder(cache, innerRows, containerCount, priLayers, true, occupiedSet)
|
if (not locs or #locs == 0) and #secLayers > 0 then
|
locs = tryAssignFixedLayerOrder(cache, innerRows, containerCount, secLayers, true, occupiedSet)
|
end
|
if not locs or #locs == 0 then
|
locs = tryAssignFixedLayerOrder(cache, outerRows, containerCount, priLayers, false, occupiedSet)
|
if (not locs or #locs == 0) and #secLayers > 0 then
|
locs = tryAssignFixedLayerOrder(cache, outerRows, containerCount, secLayers, false, occupiedSet)
|
end
|
end
|
if not locs or #locs == 0 then
|
return false, string.format("容器%s在巷道%d无可用货位", cntr_code, aisle)
|
end
|
|
for _, loc in ipairs(locs) do
|
occupiedSet[loc.S_CODE] = true
|
lua.Debug(strLuaDEID, debug.getinfo(1), "分配货位", loc.S_CODE)
|
end
|
|
table.insert(result, {
|
taskNo = task.taskNo or "",
|
containerCode = cntr_code,
|
recommendLocation = locs[1].S_CODE
|
})
|
end
|
|
return true, result
|
end
|
|
function ams_base.PICK_LOC(strLuaDEID, strJsonParam)
|
local success, ret = Recommend(strLuaDEID, strJsonParam)
|
if not success then return 2, ret end
|
return 0, json.encode(ret)
|
end
|
|
|
function ams_base.OperationCancel(strLuaDEID, body)
|
-- 输入参数验证
|
if not body or not body.code then
|
return 1, "请求参数错误缺少code"
|
end
|
|
local nRet, strRetInfo
|
local operation_objs, operation, task_objs, wave_obj
|
local cancel_count = 0 -- 取消作业数量
|
|
-- 1. 获取作业信息
|
nRet, operation = wms_op.GetInfo(strLuaDEID, body.code)
|
if nRet ~= 0 then
|
return 1, "获取作业信息失败: "..tostring(operation)
|
end
|
lua.Debug(strLuaDEID, debug.getinfo(1), "operation", operation)
|
|
-- 2. 检查作业状态是否可取消
|
-- bs_state=2(完成)不可取消, task_state=2(已开始执行)不可取消
|
if operation.bs_state == 2 then
|
return 1, "作业已完成,不可取消"
|
end
|
if operation.task_state == 2 then
|
return 1, "作业任务已开始执行,不可直接取消"
|
end
|
|
-- 3. 查询待取消的任务
|
local strCondition = "S_OP_CODE = '"..operation.code.."' AND (N_B_STATE = 0 OR N_B_STATE = 1)"
|
nRet, task_objs = m3.QueryDataObject(strLuaDEID, "Task", strCondition)
|
if nRet ~= 0 then
|
return 1, "获取任务信息失败: "..operation.code
|
end
|
if not task_objs or #task_objs == 0 then
|
return 1, "作业下无符合条件的任务: "..operation.code
|
end
|
|
-- 4. 更新任务状态为取消(5)
|
strUpdateSql = "N_B_STATE = 5"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "Task", strCondition, strUpdateSql)
|
if nRet ~= 0 then
|
return 1, "更新任务状态失败: "..tostring(strRetInfo)
|
end
|
|
-- 5. 更新作业状态为取消
|
nRet, strRetInfo = wms_op.SetCancel(strLuaDEID, operation)
|
if nRet ~= 0 then
|
return 1, "更新作业状态失败: "..tostring(strRetInfo)
|
end
|
|
-- 6. 处理波次相关逻辑
|
if operation.bs_type == "Inbound_Wave" then
|
nRet, wave_obj = m3.GetDataObjectByKey(strLuaDEID, operation.bs_type, "S_WAVE_NO", operation.bs_no)
|
if nRet ~= 0 then
|
return 1, "获取入库波次信息失败: "..tostring(wave_obj)
|
end
|
|
-- 入库波次状态=6(关闭中)时需要触发强制完成
|
if wave_obj.b_state == 6 then
|
local add_wfp = {
|
wfp_type = 1,
|
cls = "Inbound_Wave",
|
obj_id = wave_obj.id,
|
obj_name = "入库波次号'"..operation.bs_no.."'-->强制完成",
|
trigger_event = "强制完成"
|
}
|
nRet, strRetInfo = m3.AddSysWFP(strLuaDEID, add_wfp)
|
if nRet ~= 0 then
|
return 1, "添加强制完成事件失败: "..tostring(strRetInfo)
|
end
|
end
|
elseif operation.bs_type == "Outbound_Wave" then
|
nRet, wave_obj = m3.GetDataObjectByKey(strLuaDEID, operation.bs_type, "S_WAVE_NO", operation.bs_no)
|
if nRet ~= 0 then
|
return 1, "获取出库波次信息失败: "..tostring(wave_obj)
|
end
|
|
-- 出库波次状态=8(关闭中)时需要触发强制完成
|
if wave_obj.b_state == 8 then
|
local add_wfp = {
|
wfp_type = 1,
|
cls = "Outbound_Wave",
|
obj_id = wave_obj.id,
|
obj_name = "出库波次号'"..operation.bs_no.."'-->强制完成",
|
trigger_event = "强制完成"
|
}
|
nRet, strRetInfo = m3.AddSysWFP(strLuaDEID, add_wfp)
|
if nRet ~= 0 then
|
return 1, "添加强制完成事件失败: "..tostring(strRetInfo)
|
end
|
end
|
end
|
|
-- 7. 返回成功结果
|
return 0, "作业取消成功"
|
end
|
return ams_base
|