lzh
2025-06-19 3a6436e0c88042c6ce8dca2fe8adb0109f0ad9e4
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
---@diagnostic disable: need-check-nil
-- 佳通 GZ-WMS 系统中一些常用的函数
 
-- 根据PDA的设备号获取绑定的工位,如果客户端信息中的 num 为空,默认为PC端登录
-- PC 端登录设备号为 PC,保留这个目的是为了方便测试
-- 返回值: GT_PDA_Station 数据对象(json)
json  = require("json")
mobox = require("OILua_JavelinExt")
m3    = require("oi_base_mobox")
require("GT_InAndOutboundPolicies")
-- 自动获取登录账号的设备号,获取PDA和工位的绑定数据记录
function GT_Get_PDAStation(strLuaDEID)
    local nRet, strRetInfo
 
    local strUserLogin, strUserName
    nRet, strUserLogin, strUserName = mobox.getCurUserInfo(strLuaDEID)
    if (nRet ~= 0) then lua.Error(strLuaDEID, debug.getinfo(1), "获取当前操作人员信息失败! " .. strUserLogin) end
 
    local strUserInfo
    nRet, strUserInfo = mobox.getUserInfo(strUserLogin, 1, 1)
    if (nRet ~= 0) then lua.Error(strLuaDEID, debug.getinfo(1), "获取当前操作人员详细信息失败! " .. strUserInfo) end
 
    local user_info = json.decode(strUserInfo)
    local client_info = user_info.client_info
    if (client_info == nil) then
        lua.Error(strLuaDEID, debug.getinfo(1), "获取当前操作人员详细信息中没有返回client_info! ")
    end
 
    local pda_num = client_info.num
    if (pda_num == '' or pda_num == nil) then
        pda_num = "PC"
    end
    local pda_station = {
        pda_no = pda_num
    }
 
    -- 获取 GT_PDA_Station
    -- local strCondition = "S_PDA_NO = '" .. pda_num .. "'"
    -- local pda_station
    -- nRet, pda_station = m3.GetDataObjByCondition(strLuaDEID, "GT_PDA_Station", strCondition)
    -- -- nRet == 1 表示这个设备号的 GT_PDA_Station 记录不存在
    -- if (nRet == 1) then
    --     lua.Error(strLuaDEID, debug.getinfo(1), "设备号 = '" .. pda_num .. "' PDA没有定义PDA和工位的绑定关系!")
    -- end
    -- if (nRet ~= 0) then lua.Error(strLuaDEID, debug.getinfo(1), "获取当前操作人员详细信息失败! " .. strUserInfo) end
 
    return pda_station
end
 
-- 根据工位号获取工位绑定的 货位编码,查询【GT_PDA_Station】,如果一个工位有绑定多个货位报错
-- station_code 工位号
function GT_Get_StationLoc(strLuaDEID, station_code)
    local nRet, strRetInfo, strCondition
 
    if (station_code == '' or station_code == nil) then
        return 2, "工位号不能为空!"
    end
 
    local pad_stations
    strCondition = "S_STATION = '" .. station_code .. "'"
    nRet, pad_stations = m3.QueryDataObject(strLuaDEID, "GT_PDA_Station", strCondition)
    if (nRet ~= 0) then
        return 2, "获取【PDA工位关系】失败!" .. pad_stations
    end
    local nCount = #pad_stations
    if (nCount > 1) then
        return 2, "工位号'" .. station_code .. "'绑定了多个货位!"
    end
    if (nCount == 0) then
        return 2, "工位号'" .. station_code .. "'没有绑定货位!"
    end
    local station
    station = m3.KeyValueAttrsToObjAttr(pad_stations[1].attrs)
 
    if (station.S_START_LOC == nil or station.S_START_LOC == '') then
        return 2, "工位号'" .. station_code .. "'绑定的货位为空!"
    end
    return 0, station.S_START_LOC
end
 
-- 根据物料编码获取物料类型
-- 优先查询 中类 + 小类,未查询到以中类匹配
function GT_Get_ItemType(strLuaDEID, item_code)
    local strCondition = " S_ITEM_CODE= '" .. item_code .. "'"
    local nRet, material = m3.GetDataObjByCondition(strLuaDEID, "Material", strCondition)
    if (nRet ~= 0) then return 2, "m3.GetDataObjByCondition 失败!" .. material end
 
    -- 获取物料类型
    local sub_type = material.sub_type
    local minor_type = material.minor_type
 
    local strRetInfo
    strCondition = "S_SUB_TYPE = '" .. sub_type .. "' AND S_MINOR_TYPE = '" .. minor_type .. "'"
    nRet, strRetInfo = m3.GetDataObjByCondition(strLuaDEID, "GT_ITEM_TYPE", strCondition)
    if (nRet == 1) then
        strCondition = "S_SUB_TYPE = '" .. sub_type .. "' AND S_MINOR_TYPE IS NULL"
        nRet, strRetInfo = m3.GetDataObjByCondition(strLuaDEID, "GT_ITEM_TYPE", strCondition)
        if (nRet ~= 0) then return 2, "获取【物料属性类型】信息失败! " .. strRetInfo end
    elseif (nRet ~= 0) then
        return 2, "获取【物料属性类型】信息失败! " .. strRetInfo
    end
    local item_type = strRetInfo.type -- 物料类型
    if (item_type == nil or item_type == '') then return 1, "物料类型不能为空!" end
    return 0, item_type, material
end
 
-- 根据CG_Detail生成量表变化信息
function GT_Get_InventoryChg_ByCGDetail(strLuaDEID, wh_code, area_code, cntr_code, qty)
    local nRet, strRetInfo
 
    if (cntr_code == nil or cntr_code == '') then
        lua.Error(strLuaDEID, debug.getinfo(1),
            "WMS_Add_WHAreaQty_ByCGDetail 函数中容器编码必须有值!")
    end
 
    local chg_target = '' -- 量表变化对象
    if (wh_code ~= '' and wh_code ~= nil) then
        chg_target = ',"wh_code": "' .. wh_code .. '"'
    else
        lua.Error(strLuaDEID, debug.getinfo(1), "WMS_Add_WHAreaQty_ByCGDetail 函数中仓库编码必须有值!")
    end
    if (area_code ~= '' and area_code ~= nil) then
        chg_target = chg_target .. ',"area_code": "' .. area_code .. '"'
    end
    if (chg_target == '') then lua.Error(strLuaDEID, debug.getinfo(1), "WMS_Add_WHAreaQty_ByCGDetail 函数中量表变化对象必须有值!") end
 
    -- 获取 CG_Detail
    local strOrder = ''
    local strCondition = "S_CNTR_CODE = '" .. cntr_code .. "'"
    nRet, strRetInfo = mobox.queryDataObjAttr(strLuaDEID, "CG_Detail", strCondition, strOrder)
    if (nRet ~= 0) then lua.Error(strLuaDEID, debug.getinfo(1), "获取【容器货品明细】失败! " .. strRetInfo) end
    if (strRetInfo == '') then lua.Error(strLuaDEID, debug.getinfo(1), "容器'" .. cntr_code .. "'中没有货品!") end
 
    local retObjs = json.decode(strRetInfo)
    local nObjs = #retObjs
    local n
    local inventory_change = ''
    local cg_detail
    local inventory_info
 
    for n = 1, nObjs do
        nRet, cg_detail = m3.ObjAttrStrToLuaObj("CG_Detail", lua.table2str(retObjs[n].attrs))
        if (nRet ~= 0) then lua.Error(strLuaDEID, debug.getinfo(1), "m3.ObjAttrStrToLuaObj(CG_Detail) 失败! " .. cg_detail) end
 
        -- 生成仓库量变化输入参数
        inventory_info = '{"item_code": "' .. cg_detail.item_code .. '",'
        inventory_info = inventory_info .. '"item_name": "' .. cg_detail.item_name .. '",'
        inventory_info = inventory_info .. '"item_state": "' .. cg_detail.item_state .. '",'
        inventory_info = inventory_info .. '"item_route": "' .. cg_detail.item_route .. '",'
        inventory_info = inventory_info .. '"end_user": "' .. cg_detail.end_user .. '",'
        inventory_info = inventory_info .. '"qty": "' .. qty .. '"' .. chg_target .. '}'
 
        inventory_change = inventory_change .. inventory_info .. ","
    end
    inventory_change = lua.trim_laster_char(inventory_change)
 
    return inventory_change
end
 
-- 设置作业状态为取消
function GT_Op_SetStateByCode(strLuaDEID, op_code)
    local nBState
 
    if (op_code == nil or op_code == '') then
        return 1, "调用 WMS_Task_SetStateByCode 函数时参数不正确, 任务编码不能为空!"
    end
 
    nBState = wms_base.Get_nConst(strLuaDEID, "作业状态-取消")
 
 
    -- 根据字典获取 N_B_STATE 的显示名称
    local str_b_state = wms_base.GetDictItemName(strLuaDEID, "WMS_OperationState", nBState)
    local condition = "S_CODE = '" .. op_code .. "'"
    local strSetAttr = "N_B_STATE = " .. nBState .. ", S_B_STATE = '" .. str_b_state .. "', S_ERR=''"
    local nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "Operation", condition, strSetAttr)
    if (nRet ~= 0) then
        return nRet, "设置任务状态失败!" .. strRetInfo
    end
    return 0, "ok"
end
 
-- 自定义比较函数
local function compareByOpCount(a, b)
    return a.opCount < b.opCount
end
 
-- 获取巷道对象,按照作业数量排序
function GT_Get_Roadway(strLuaDEID)
    local nRet, strRetInfo, strCondition, attr
 
    local data = {}
    strCondition = "S_AREA_CODE = 'LK' AND N_LOCK_STATE = 0"
    nRet, strRetInfo = m3.QueryDataObject(strLuaDEID, "Roadway", strCondition)
    if (nRet ~= 0) then return 2, "获取【巷道】失败!" .. strRetInfo end
    local nCount = #strRetInfo
    if (nCount == 0) then return 2, strRetInfo end
    lua.Debug(strLuaDEID, debug.getinfo(1), "strRetInfo", strRetInfo)
 
    for i = 1, nCount do
        nRet, attr = m3.ObjAttrStrToLuaObj("Roadway", strRetInfo[i].attrs)
        if (nRet ~= 0) then return 2, "m3.ObjAttrStrToLuaObj失败!" .. attr end
        lua.Debug(strLuaDEID, debug.getinfo(1), "attr", attr)
 
        -- 获取该巷道的任务数量
        local count
        strCondition =
            "N_B_STATE IN (0,1) AND (S_START_LOC IN (SELECT S_CODE FROM TN_Location WHERE S_AREA_CODE = 'LK' AND N_ROADWAY = '" ..
            attr.roadway .. "') "
        strCondition = strCondition ..
            "OR S_END_LOC IN (SELECT S_CODE FROM TN_Location WHERE S_AREA_CODE = 'LK' AND N_ROADWAY = '" ..
            attr.roadway .. "'))"
        nRet, count = mobox.getDataObjCount(strLuaDEID, "Operation", strCondition)
        if (nRet ~= 0) then return 2, "getDataObjCount失败!" .. count end
 
        local list = {
            roadway = attr.roadway,
            opCount = count
        }
 
        data[i] = list
    end
    lua.Debug(strLuaDEID, debug.getinfo(1), "data", data)
 
    -- 排序
    table.sort(data, compareByOpCount)
    lua.Debug(strLuaDEID, debug.getinfo(1), "data", data)
    return 0, data
end
 
-- 获取任务最少的可用巷道
function LeastTaskRoadway(strLuaDEID, roadway)
    local a = ''          -- 任务数量最少的巷道
    local b = tonumber(0) -- 用来计数的变量
    -- 获取未上锁的巷道
    local condition = ""
    if (roadway ~= nil and roadway ~= '') then
        condition = "N_ROADWAY IN(" .. roadway .. ") AND "
    end
    condition = condition .. "N_LOCK_STATE = 0 AND S_AREA_CODE = 'LK'"
    local nRet, strRetInfo = m3.QueryDataObject(strLuaDEID, "Roadway", condition)
    if (nRet ~= 0) then return 2, "获取【常量】信息失败! " .. strRetInfo end
    if (strRetInfo == nil or strRetInfo == '') then return 2, '未查询到可用巷道!' end
 
    for i = 1, #strRetInfo do
        -- 获取巷道对象并格式转换
        local attr
        nRet, attr = m3.ObjAttrStrToLuaObj("Roadway", lua.table2str(strRetInfo[i].attrs))
        if (nRet ~= 0) then return 2, "m3.ObjAttrStrToLuaObj失败! " .. attr end
 
        -- 获取该巷道的任务数量
        local count
        condition = "N_B_STATE IN (0,1) AND N_ROADWAY = '" .. attr.roadway .. "'"
        nRet, count = mobox.getDataObjCount(strLuaDEID, "Task", condition)
        if (nRet ~= 0) then return 2, "getDataObjCount失败!" .. count end
        -- 该巷道的任务数大于最
        if (i == 1) then
            a = attr.roadway
            b = tonumber(count)
        elseif (tonumber(count) < b) then
            a = attr.roadway
            b = tonumber(count)
        end
    end
    return 0, a -- 返回任务数量最少的巷道
end
 
-- 调用接口并创建接口异常处理记录
function CreateInterfaceExc(strLuaDEID, strurl, strHeader, strBody, type, interface_name)
    local nRet, strRetInfo = mobox.sendHttpRequest(strurl, strHeader, lua.table2str(strBody))
    if (nRet ~= 0) then
        return 2, "调用接口失败!" .. strRetInfo
    end
    if (strRetInfo == nil or strRetInfo == '') then
        return 2, "调用接口返回为空!"
    else
        local success, resJson = pcall(json.decode, strRetInfo)
        if (success == false) then return 2, "非法的JSON格式!" .. resJson end
        lua.Debug(strLuaDEID, debug.getinfo(1), "resJson", resJson)
 
        local errcode, message
        if (type == 'WCS') then
            errcode = tonumber(resJson.result_flag)
            message = resJson.err_msg
        elseif (type == 'AGV') then
            errcode = tonumber(resJson.code)
            message = resJson.msg
        elseif (type == 'GTWMS') then
            success = resJson.success
            message = resJson.message
        end
 
        local exc = m3.AllocObject(strLuaDEID, "GT_Interface_Exc")
        exc.source = type
        exc.interface_name = interface_name
        exc.url = strurl
        exc.body = lua.table2str(strBody)
        if (type == 'WCS' or type == 'AGV') then
            if (errcode ~= 0) then
                exc.state = "失败"
                exc.err = message
            end
        elseif (type == 'GTWMS') then
            if (success ~= true) then
                exc.state = "失败"
                exc.err = message
            end
        end
        nRet, exc = m3.CreateDataObj(strLuaDEID, exc)
        if (nRet ~= 0) then return 2, '创建【接口异常记录】失败!' .. exc end
    end
    return 0, ""
end
 
-- 判断货位是否是内深位,是则返回true和对应的外深位,不是则返回false
function GetPosLoc(strLuaDEID, loc_code)
    -- 获取货位信息
    local nRet, location = wms_wh.Location_GetInfo(strLuaDEID, loc_code)
    if (nRet ~= 0) then lua.Error(strLuaDEID, debug.getinfo(1), "获取【货位】信息失败!" .. strRetInfo) end
 
    -- 判断货位是否是内深位,不是内深位则返回
    if (tonumber(location.pos) == 1) then return false, "" end
 
    local loc_code_table = lua.split(loc_code, "-") -- 通过符号分割字符串为数组
    local loc_row = loc_code_table[2]
 
    -- 通过库区、排组号 定位巷道信息
    local roadway
    local strCondition = "S_AREA_CODE = 'LK' AND (N_LEFT_ROW_GROUP = "
        .. location.row_group .. " or N_RIGHT_ROW_GROUP = " .. location.row_group .. " )"
    nRet, roadway = m3.GetDataObjByCondition(strLuaDEID, "Roadway", strCondition)
    if (nRet ~= 0) then lua.Error(strLuaDEID, debug.getinfo(1), "获取【巷道】信息失败!" .. roadway) end
 
    local row = "" -- 所属巷道信息中的 (内/外 深位)2排 的字符串信息(例: 21,22,)
    if (location.row_group == tonumber(roadway.left_row_group)) then
        row = roadway.left_row
    else
        row = roadway.right_row
    end
    local row_table = lua.split(row, ",")
    local str = ""
    for j = 1, #row_table do
        if (loc_row ~= row_table[j]) then
            str = row_table[j]
        end
    end
    if (#str == 1) then str = "0" .. str end
 
    local new_loc_code = loc_code_table[1] .. "-" .. str .. "-" .. loc_code_table[3] .. "-" .. loc_code_table[4]
    return true, new_loc_code
end
 
-- 容器校验是否加锁,如果没加锁则加锁
function SetCntrLock(strLuaDEID, cntr_code, op_code, type)
    -- 获取容器信息
    local nRet, container = wms_cntr.GetInfo(strLuaDEID, cntr_code)
    if (nRet ~= 0) then return 2, '获取容器对象失败!' .. container end
 
    if(tonumber(container.lock_state) ~= 0)then
        return 2, '容器已被锁定!' .. container
    end
    nRet, container = wms_cntr.SetLock(strLuaDEID, container, type, op_code)
    if (nRet ~= 0) then return 2, '托盘容器添加出库锁失败!' .. strRetInfo end
 
    return 0,""
end