1
Jianw
9 天以前 70f29da38121b9a467841253e3268feb5df02902
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
--[[
    编码: WMS-20-26#1
    名称: 入库预分配料箱1#算法
    作者:HAN  
    日期:2025-1-29
 
    级别:项目
         来源项目巨星料箱库, 选中多个入库单合并生成入库波次,然后调用后台呼出料箱算法
         适用多入库单合并成一个入库波次的处理
 
    函数: RunEmptyBoxOutProcess
 
    功能:
        -- 后台脚本计算入库需要呼出多少空料箱
 
    更改记录:
        V3.0 HAN 20241231 改成后台线程来处理空料箱呼出计算,因为这个过程是一个比较长的事务,有并发锁表的风险
                          本次改进的目的就是将这些长事务统一交给后台一个线程排队处理
--]]
 
wms_pac = require ("wms_pac_cbg")           -- 空料箱预先分配算法
 
-- 生成波次入库明细
-- strIONo 入库单号
-- wave_detail [{item_name,item_code,qty,weight,volume,cell_type}]
local function generate_wave_detail( strLuaDEID, strIONo, wave_detail )
    local nRet, strRetInfo
    local strCondition
    local data_objs
 
    strCondition = "S_IO_NO = '"..strIONo.."'"
    nRet, data_objs = m3.QueryDataObject(strLuaDEID, "Inbound_Detail", strCondition, "N_ROW_NO" )
    if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objs end
    if ( data_objs == '' ) then return 0  end
    
    local n, item_code, qty, weight, volume
    local detail_attrs
    local bFind
    for n = 1, #data_objs do
        detail_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
        item_code = lua.Get_StrAttrValue( detail_attrs.S_ITEM_CODE )
        qty = lua.StrToNumber( detail_attrs.F_QTY )
        weight = lua.StrToNumber( detail_attrs.F_WEIGHT )
        volume = lua.StrToNumber( detail_attrs.F_VOLUME )
        if ( item_code ~= '' and qty > 0 ) then
            bFind = false
            for m = 1, #wave_detail do
                if (wave_detail[m].item_code == item_code) then
                    bFind = true
                    wave_detail[m].qty = wave_detail[m].qty + qty
                    break
                end
            end
            if ( bFind == false ) then
                local wave_item = {
                    item_code = item_code,
                    item_name = lua.Get_StrAttrValue( detail_attrs.S_ITEM_NAME ),
                    qty = qty,
                    weight = weight,
                    volume = volume,
                    cell_type = lua.Get_StrAttrValue( detail_attrs.S_CELL_TYPE )
                }
                table.insert( wave_detail, wave_item )
            end
        end
    end
    return 0
end
 
-- 返回结果 result = { cntr_count = 2, wave_obj_id = "", cntr_cell_list = {}}
--[[ datajson 格式: 
    parameter = {
        station = station,
        login = strUserLogin,
        user_name = strUserName,
        data_json = data_json
    } 
]]
 
function RunEmptyBoxOutProcess ( strLuaDEID ) 
    local nRet, strRetInfo, n
    local parameter, data_json
    local result = { cntr_count = 0 }
 
    m3.PrintLuaDEInfo( strLuaDEID )
    
    nRet, parameter = m3.GetSysDataJson( strLuaDEID )
    if (nRet ~= 0) then 
        lua.Stop( strLuaDEID, data_json )
        return 1
    end
    
    data_json = parameter.data_json
    nCount = #data_json
    if ( nCount == 0 ) then 
        result = { cntr_count = 0 }
        mobox.returnValue( strLuaDEID, RETSTR_TYPE.Json, lua.table2str(result) )
        return 0
    end
    
    -- 从入库单这里获取 仓库、库区编码,如果不一样报错
    local station = lua.Get_StrAttrValue( parameter.station )
    local wh_code = ''
    local area_code = ''
    local compose = {}
    local obj_attrs, strCondition
    local wave_detail_list = {}
    local inbound_order
 
    for n = 1, nCount do
        obj_attrs = m3.KeyValueAttrsToObjAttr( data_json[n].attrs )
        -- 判断一下入库单是否有安排了波次,如果有就终止程序
        strCondition = "S_ID = '"..lua.trim_guid_str( data_json[n].id ).."'"
        nRet, inbound_order = m3.GetDataObjByCondition(strLuaDEID, "Inbound_Order", strCondition )
        if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), inbound_order ) end
        if ( lua.Get_StrAttrValue( inbound_order.wave_no ) ~= '' ) then
            lua.Stop( strLuaDEID, "入库单'"..inbound_order.no.."'已经有入库波次,波次号 = '"..inbound_order.wave_no.."'" )
            return  1
        end
 
        local item = m3.AllocObject(strLuaDEID,"IW_Compose")
        item.po_no = obj_attrs.S_NO
        item.wave_no = ''
        if ( wh_code == '' ) then
            wh_code = lua.Get_StrAttrValue( obj_attrs.S_WH_CODE )
        else
            if ( wh_code ~= obj_attrs.S_WH_CODE ) then
                lua.Stop( strLuaDEID, "选中的入库单仓库必须是一样的!" )
                return  1
            end
        end
        if ( area_code == '' ) then
            area_code = lua.Get_StrAttrValue( obj_attrs.S_AREA_CODE )
        else
            if ( area_code ~= obj_attrs.S_AREA_CODE ) then
                lua.Stop( strLuaDEID, "选中的入库单库区必须是一样的!" )
                return  1
            end
        end
        -- 获取商品重量和数量累计
        nRet, strRetInfo = generate_wave_detail( strLuaDEID, obj_attrs.S_NO, wave_detail_list )
        if (nRet ~= 0) then 
            lua.Stop( strLuaDEID,  "generate_wave_detail 失败!"..strRetInfo )
            return 1 
        end
 
        table.insert( compose, item )
    end
    if ( wh_code == '' ) then
        lua.Stop( strLuaDEID, "入库单列表栅格中仓库列不能为空!" )
        return  1
    end 
    if ( area_code == '' ) then
        lua.Stop( strLuaDEID, "入库单列表栅格中必须有有库区列!" )
        return  1
    end     
    
    -- 计算货品件数,种类
    local total_qty = 0
    local good_type_num = #wave_detail_list
 
    for n = 1, good_type_num do
        total_qty = total_qty + wave_detail_list[n].qty
    end
 
    local item_list = {}    -- 需要入库的货品
    local obj_attrs
 
    -- 生成要入库的货品链表 item_list
    for n = 1, good_type_num do
        local item = {
            item_code = wave_detail_list[n].item_code,
            item_name = wave_detail_list[n].item_name,
            row = n,
            volume = wave_detail_list[n].volume,
            weight = wave_detail_list[n].weight,
            cell_type = wave_detail_list[n].cell_type,
            qty = wave_detail_list[n].qty,
            alloc_qty = 0,
            cntr_cell_list = {},
            empty_cell_type = "",
            upgrad_cell_index = 0,          -- 标记货品开始升格的料格 A = 1, B = 2 ,如果到A还没有合适料格,要从这个料格开始降格
            Q = 0,
            ok = false                      -- true 表示这个货品已经分配好入库料箱
        }
        table.insert( item_list, item )
    end
 
    -- 创建波次
    local wave = m3.AllocObject(strLuaDEID,"Inbound_Wave")
    wave.wh_code = wh_code
    wave.area_code = area_code
    wave.station = station
    wave.factory = parameter.factory
    wave.operator_name = lua.Get_StrAttrValue( parameter.user_name )
    wave.operator = lua.Get_StrAttrValue( parameter.login )
    wave.good_type_num = good_type_num
    wave.total_qty = total_qty
 
    nRet, wave = m3.CreateDataObj( strLuaDEID, wave )
    if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【入库波次】对象失败!'..wave ) end      
 
    -- 创建波次组成
    local strUpdateSql
    for n = 1, nCount do
        compose[n].wave_no = wave.wave_no
        nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, compose[n] )
        if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【入库波次组成】对象失败!'..strRetInfo ) end    
        strUpdateSql = "S_WAVE_NO = '"..wave.wave_no.."', S_STATION_NO = '"..wave.station.."', S_OPERATOR_NAME = '"..wave.operator_name.."',"
        -- N_B_STATE = 1 表示入库单已经组盘
        strUpdateSql = strUpdateSql.."S_OPERATOR = '"..wave.operator.."', N_B_STATE = 1"
        strCondition = "S_NO = '"..compose[n].po_no.."'"
        nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Inbound_Order", strCondition, strUpdateSql )
        if ( nRet ~= 0 ) then  lua.Error( strLuaDEID, debug.getinfo(1), "更新【入库单】信息失败!"..strRetInfo ) end               
    end
 
    -- 创建波次明细
    local wave_detail
    for n = 1, #wave_detail_list do
        wave_detail = m3.AllocObject(strLuaDEID,"IW_Detail")
        wave_detail.wave_no = wave.wave_no
        wave_detail.row_no = n
        wave_detail.item_code = wave_detail_list[n].item_code
        wave_detail.item_name = wave_detail_list[n].item_name
        wave_detail.cell_type = wave_detail_list[n].cell_type
        wave_detail.qty = wave_detail_list[n].qty
        wave_detail.weight = wave_detail_list[n].weight
        wave_detail.volume = wave_detail_list[n].volume
        nRet, strRetInfo = m3.CreateDataObj( strLuaDEID, wave_detail )
        if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), '创建【入库波次明细】对象失败!'..strRetInfo ) end          
    end
 
    -- 呼出空料箱算法
    local pac_list = {}
    local pac_detail_list = {}    
    local enable_aisle = ""             -- 可用巷道
 
    nRet, enable_aisle = prj_base.Get_Available_Aisle( strLuaDEID, area_code )
    if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), 'prj_base.Get_Available_Aisle!'..enable_aisle ) end
    if ( enable_aisle == '' ) then
        lua.Stop( strLuaDEID,  "库区里的所有堆垛机状态都是不可用,无法继续呼出料箱!")
        return 1
    end       
 
    --[[
    local ctd_code
    nRet, ctd_code = wms_base.Get_sConst( strLuaDEID, "WMS_Default_CNTR_Type" )
    if ( nRet ~= 0 ) then
        lua.Stop( strLuaDEID, "系统没有定义常量 WMS_Default_CNTR_Type") )
        return
    end
    if ( ctd_code == '' ) then
        lua.Stop( strLuaDEID, "常量 WMS_Default_CNTR_Type 的值不能为空!") )
        return
    end
    ]]
 
    -- 组织预分配料箱呼出时的配置参数
    local pac_parameter = {
        factory = parameter.factory,
        wh_code = wh_code, area_code = area_code, 
        station = station, 
        aisle = enable_aisle,
        bs_type = "Inbound_Wave", bs_no = wave.wave_no,
        cntr_out_op_def = parameter.cntr_out_op_def or '',
        cntr_back_op_def = parameter.cntr_back_op_def or ''        
    }
    nRet, strRetInfo = wms_pac.Pre_Alloc_Cntr( strLuaDEID, item_list, pac_parameter, pac_list, pac_detail_list )  
    if ( nRet ~= 0 ) then
        lua.Stop( strLuaDEID, "Pre_Alloc_Cntr 错误: "..strRetInfo)
        return 1
    end    
 
    result = { 
        cntr_count = #pac_list,
        cntr_cell_list = pac_detail_list,
        cls_id = "Inbound_Wave",
        obj_id = wave.id
    }
    mobox.returnValue( strLuaDEID, RETSTR_TYPE.Json, lua.table2str(result) )
 
    return 0
end