wsz
2025-06-10 4be5e6f4ae34bcb7cb47f05816421459bbfaedf1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
--[[
    版本:    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