--[[
|
版本: Version 2.1
|
创建日期: 2025-1-28
|
创建人: HAN
|
|
WMS-Basis-Model-Version: V15.5
|
|
功能:
|
WMS 过程中对一些货位分配方面的基本算法
|
|
-- GetAreaLocTaskNumber 获取某个区域中的货位任务数量,返回一个货位任务列表
|
--]]
|
|
json = require ("json")
|
mobox = require ("OILua_JavelinExt")
|
wms = require ("OILua_WMS")
|
lua = require ("oi_base_func")
|
m3 = require ("oi_base_mobox")
|
|
local wms_alg = {_version = "0.2.1"}
|
|
-- 根据货位的任务数量进行排序,小的在前面
|
local function loc_tasknum_sort( loc1, loc2 )
|
return loc1.task_num < loc2.task_num
|
end
|
--[[
|
获取某个区域中的货位任务数量,返回一个货位任务列表, 一般这样的区域是接驳区,理货区
|
输入参数:
|
area_code -- 库区编码
|
返回参数:
|
nRet
|
loc_list (area_code库区中货位基本信息)
|
--]]
|
function wms_alg.GetAreaLocTaskNumber( strLuaDEID, area_code )
|
local nRet, strRetInfo
|
|
if ( area_code == nil or area_code == '') then
|
return 1, "wms_alg.GetAreaLocTaskNumber 函数中的 area_code 必须有值!"
|
end
|
|
-- 获取库区货位的使用情况
|
local strCondition = "C_ENABLE = 'Y' AND S_AREA_CODE = '"..area_code.."'"
|
local strOrder = "S_CODE"
|
local loc_objs, loc_info
|
local loc_list = {}
|
local task_num
|
|
nRet, loc_objs = m3.QueryDataObject( strLuaDEID, "Location", strCondition, strOrder )
|
if (nRet ~= 0) then lua.Error( strLuaDEID, debug.getinfo(1), "获取【Location】信息失败! " .. loc_objs ) end
|
for n = 1, #loc_objs do
|
obj_attrs = m3.KeyValueAttrsToObjAttr(loc_objs[n].attrs)
|
|
-- 获取该货位的出入库任务数量
|
-- N_B_STATE < 3 表示任务的状态为 0等待/1已推送/2执行中, 任务有一个点在 storage_area 的巷道 aisle
|
-- 任务包括进出
|
strCondition = "N_B_STATE < 3 AND ( S_START_LOC = '"..obj_attrs.S_CODE.."' or S_END_LOC = '"..obj_attrs.S_CODE.."')"
|
nRet, strRetInfo = mobox.getDataObjCount( strLuaDEID, "Task", strCondition )
|
if ( nRet ~= 0 ) then return nRet, strRetInfo end
|
task_num = lua.StrToNumber( strRetInfo )
|
local loc_info = {
|
loc_code = obj_attrs.S_CODE,
|
capacity = lua.StrToNumber( obj_attrs.N_CAPACITY ),
|
cur_num = lua.StrToNumber( obj_attrs.N_CURRENT_NUM ),
|
task_num = task_num, -- 任务数量
|
abc_cls = "" -- ABC 分类
|
}
|
table.insert( loc_list, loc_info )
|
end
|
table.sort( loc_list, loc_tasknum_sort )
|
return 0, loc_list
|
end
|
|
-- 排序
|
local function aisle_loc_sort( loc1, loc2 )
|
if ( loc1.abc_cls < loc2.abc_cls ) then
|
return true
|
elseif ( loc1.abc_cls == loc2.abc_cls ) then
|
-- 距离入口近的优先
|
return loc1.weight < loc2.weight
|
end
|
return false
|
end
|
|
--[[
|
已知巷道号获取巷道内空货位,如果一次搬运两个料箱希望货位在相邻列同层次,否则计算两个货位,优先级
|
如果是双工位,货位计算优先级
|
1 -- 有相邻2个货位
|
2 -- 和第一个货位最近,比如上面,下面,左边,右边一格
|
输入参数:
|
area_code -- 巷道所在库区
|
aisle -- 巷道号
|
|
order_method -- 0 -- 根据货位中的 weight/weight2(权重) 进行排序 1 -- 先放满层 2 -- 先放满列
|
loc_order -- 0 表示列值最小的就在出库口, 1 -- 相反列值最大的在巷道口
|
strAddCondition -- 附加条件 (可以不输入默认为空)
|
loc_num -- 需要的货位数量 1个或2个 2 表示是双工位堆垛机 可以不输入默认=1
|
返回:
|
{
|
loc_code
|
adjacent_loc -- 相邻空货位
|
}
|
]]
|
|
function wms_alg.Get_Aisle_Empty_Loc( strLuaDEID, area_code, aisle, order_method, loc_order, strAddCondition, loc_num )
|
local nRet, strRetInfo
|
local loc_list = {}
|
|
if ( loc_num == nil or type(loc_num) ~= "number") then loc_num = 1 end
|
if ( loc_order == nil or type(loc_order) ~= "number" ) then loc_order = 0 end
|
if ( order_method == nil or type(order_method) ~= "number" ) then order_method = 0 end
|
if ( strAddCondition == nil or type(strAddCondition) ~= "string" ) then strAddCondition = '' end
|
|
-- 获取巷道内所有空货位的顺序设置
|
local strOrder = ""
|
if ( order_method == 0 ) then
|
-- 根据权重排序
|
strOrder = "N_POS_WEIGHT"
|
-- 说明堆垛机是从列值最大的入口进入巷道
|
if ( loc_order == 1 ) then strOrder = "N_POS_WEIGHT_2" end
|
elseif ( order_method == 1 ) then
|
-- 先放满最下面的层
|
if ( loc_order == 0 ) then
|
strOrder = "N_LAYER, N_COL"
|
else
|
strOrder = "N_LAYER, N_COL desc"
|
end
|
elseif ( order_method == 2 ) then
|
-- 先放满最靠近巷道口的列
|
if ( loc_order == 0 ) then
|
strOrder = "N_COL, N_LAYER"
|
else
|
strOrder = "N_COL desc, N_LAYER"
|
end
|
else
|
return 1, "wms_alg.Get_Aisle_Empty_Loc 函数目前不支付 order_method = "..order_method.." 的算法!"
|
end
|
|
local loc_objs
|
local count
|
|
if ( loc_num == 1 ) then
|
count = 1
|
else
|
count = 100
|
end
|
strCondition = "S_AREA_CODE = '"..area_code.."' AND N_CURRENT_NUM = 0 AND N_LOCK_STATE = 0 AND N_AISLE = "..aisle
|
if ( strAddCondition ~= '' ) then
|
strCondition = strCondition.." AND ("..strAddCondition..")"
|
end
|
|
lua.Debug( strLuaDEID, debug.getinfo(1), "strOrder", strOrder )
|
|
nRet, loc_objs = m3.QueryDataObject3(strLuaDEID, "Location", strCondition, strOrder, count )
|
if (nRet ~= 0) then return 2, "QueryDataObject失败!"..loc_objs end
|
if ( loc_objs == '') then return 1, "没有空货位" end
|
|
local n
|
local loc_obj = {}
|
local weight, weight2
|
|
if ( loc_num == 1 ) then
|
loc_obj = m3.KeyValueAttrsToObjAttr(loc_objs[1].attrs)
|
if ( loc_order == 0 ) then
|
weight = lua.Get_NumAttrValue( loc_obj.N_POS_WEIGHT )
|
else
|
weight = lua.Get_NumAttrValue( loc_obj.N_POS_WEIGHT2 )
|
end
|
local loc = {
|
loc_code = loc_obj.S_CODE,
|
row = lua.Get_NumAttrValue( loc_obj.N_ROW ),
|
col = lua.Get_NumAttrValue( loc_obj.N_COL ),
|
layer = lua.Get_NumAttrValue( loc_obj.N_LAYER ),
|
weight = weight,
|
abc_cls = '', -- ABC 分类
|
adjacent_loc = '' -- 相邻货位
|
}
|
table.insert( loc_list, loc )
|
else
|
local nCount = #loc_objs
|
if ( nCount < 2 ) then return 1, "没有空货位" end
|
|
if ( nCount == 2 ) then
|
loc_obj = m3.KeyValueAttrsToObjAttr(loc_objs[1].attrs)
|
loc_obj2 = m3.KeyValueAttrsToObjAttr(loc_objs[2].attrs)
|
if ( loc_order == 0 ) then
|
weight = lua.Get_NumAttrValue( loc_obj.N_POS_WEIGHT )
|
else
|
weight = lua.Get_NumAttrValue( loc_obj.N_POS_WEIGHT2 )
|
end
|
local loc = {
|
loc_code = loc_obj.S_CODE,
|
row = lua.Get_NumAttrValue( loc_obj.N_ROW ),
|
col = lua.Get_NumAttrValue( loc_obj.N_COL ),
|
layer = lua.Get_NumAttrValue( loc_obj.N_LAYER ),
|
weight = weight,
|
abc_cls = '', -- ABC 分类
|
adjacent_loc = loc_obj2.S_CODE -- 相邻货位
|
}
|
table.insert( loc_list, loc )
|
else
|
for n = 1, nCount do
|
loc_obj = m3.KeyValueAttrsToObjAttr(loc_objs[n].attrs)
|
if ( loc_order == 0 ) then
|
weight = lua.Get_NumAttrValue( loc_obj.N_POS_WEIGHT )
|
else
|
weight = lua.Get_NumAttrValue( loc_obj.N_POS_WEIGHT2 )
|
end
|
local loc = {
|
loc_code = loc_obj.S_CODE,
|
row = lua.Get_NumAttrValue( loc_obj.N_ROW ),
|
col = lua.Get_NumAttrValue( loc_obj.N_COL ),
|
layer = lua.Get_NumAttrValue( loc_obj.N_LAYER ),
|
weight = weight,
|
abc_cls = '',
|
adjacent_loc = ''
|
}
|
table.insert( loc_list, loc )
|
end
|
|
-- ABC分类,有两个紧邻的空货位的优先,设置为A,其余为B
|
for n = 1, nCount do
|
-- 不是最好一个空货位,最后一个空货位不需要判断是否有相邻货位
|
if ( n < nCount ) then
|
-- 判断和下一个货位的weight的差距是否=1
|
for m = n+1, nCount do
|
if ( loc_list[m].weight == (loc_list[n].weight + 1) ) then
|
-- 判断是否同排同层
|
if ( loc_list[m].row == loc_list[n].row and
|
loc_list[m].layer == loc_list[n].layer ) then
|
loc_list[n].abc_cls = "A"
|
loc_list[n].adjacent_loc = loc_list[m].loc_code
|
break
|
end
|
else
|
loc_list[n].abc_cls = "B"
|
break
|
end
|
end
|
else
|
loc_list[n].abc_cls = "B"
|
end
|
end
|
-- 重新排序
|
table.sort( loc_list, aisle_loc_sort )
|
|
if ( loc_list[1].abc_cls ~= 'A' ) then
|
loc_list[1].adjacent_loc = loc_list[2].loc_code
|
end
|
end
|
end
|
return 0, loc_list[1]
|
end
|
|
return wms_alg
|