--[[ 版本: 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