1
Jianw
2025-07-09 88e26a2a960dbbc148332772448b79b9877102d8
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
--[[
   编码: WMS-60-12
   名称: 自动配盘
   作者:
   日期: 2025-1-29
 
   函数: AutoDistribution
   功能:
        -- 根据出库波次明细计算出配盘及配盘明细,再把出库货品批分到各出库单绑定的拣料箱
 
   备注:
        -- 该程序起源巨星二期料箱库,适合多料格料箱的出库分拣操作
        
   更改记录:
        V2.0 合并取消 combine_cntr_detail
--]]
wms_out = require( "wms_outbound" )
wms_station = require( "wms_station" )
 
local function get_d_cntr_detail_by_bs_no( d_cntr_detail_list, bs_no )
    local sub_d_cntr_detail_list = {}
    local n
 
    for n = 1, #d_cntr_detail_list do
        if ( d_cntr_detail_list[n].bs_no == bs_no ) then
            table.insert( sub_d_cntr_detail_list, d_cntr_detail_list[n])
        end
    end
    return sub_d_cntr_detail_list
end
 
-- 把配盘明细中相同料格的货品数量进行合并
-- Distribution_CNTR_Detail 合并,在出库的时候一个料格可能会有多条CG_Detail
local function combine_cntr_detail( d_cntr_detail_list )
    local n
    local combine_result = {}
 
    for n = 1, #d_cntr_detail_list do
        find = false
        for m = 1, #combine_result do
            if ( d_cntr_detail_list[n].cntr_code == combine_result[m].cntr_code and d_cntr_detail_list[n].cell_no == combine_result[m].cell_no ) then
                if ( d_cntr_detail_list[n].item_code ~= combine_result[m].item_code ) then
                    return 1, "合并配盘明细发生错误, 相同的料格存在不同编码的货品!"
                end
                find = true
                combine_result[m].qty = combine_result[m].qty + d_cntr_detail_list[n].qty
                -- MDF BY HAN 20250314
                combine_result[m].cg_detail_id = ""     -- 多条合并后CG_Detail要设置为空
            end
        end
 
        if ( find == false ) then
            table.insert( combine_result, d_cntr_detail_list[n] )
        end
    end
 
    return 0, combine_result
end
 
--[[
        执行'自动配盘算法1#' 来源巨星二期料箱库
 
        datajson 格式:
        {
            station = station,
            login = strUserLogin,
            user_name = strUserName,
            wave_no = wave.wave_no              -- 出库波次号        
        }
--]]
function AutoDistribution( strLuaDEID )
    local nRet, strRetInfo
    local parameter
    -- 获取输入参数 datajson
    nRet, parameter = m3.GetSysDataJson( strLuaDEID )
    if (nRet ~= 0) then 
        lua.Stop( strLuaDEID, parameter )
        return 1
    end
    local  wave_no = parameter.wave_no or ''
 
    if wave_no == '' then
        lua.Stop( strLuaDEID, "脚本的输入参数中,出库波次号 wave_no 不能为空!")
        return
    end
    local strCondition = "S_WAVE_NO = '"..wave_no.."'"
    local out_wave  
    nRet, out_wave = m3.GetDataObjByCondition( strLuaDEID, "Outbound_Wave", strCondition )
    if ( nRet ~= 0 ) then  
        lua.Stop( strLuaDEID, "获取【出库波次】信息失败!"..out_wave )
        return
    end  
 
    -- 获取出库波次对象属性
 
    local b_state = lua.Get_NumAttrValue( out_wave.b_state )  
    local wh_code = lua.Get_StrAttrValue( out_wave.wh_code )
    local area_code = lua.Get_StrAttrValue( out_wave.area_code ) 
    local station = lua.Get_StrAttrValue( parameter.station )  
 
    local err_msg = ''
    local n, m
    local d_cntr_list = {}              -- 配盘/Distribution_CNTR
    local d_cntr_detail_list = {}       -- 配盘明细/Distribution_CNTR_Detail   
    local oo_no_set = {} 
    local loc_code
    nRet, loc_code = wms_station.Get_Station_Loc( strLuaDEID, station )
    if ( nRet ~= 0 ) then
        lua.Stop( strLuaDEID, loc_code )
        return
    end 
 
    local detail_attrs, ow_compose
    local outbound_detail_list
    local data_objs    
    local pickbox_volume = wms_base.Get_nConst( strLuaDEID, "拣料箱体积")
    local oo_obj_attrs
    local pick_box_num
    local pick_box_code
    local new_d_cntr_detail_list = {}        -- 加了拣料箱编码后的 【配盘明细】
    local shortage_list = {}
    local exit_loc
    nRet, exit_loc = wms_wh.GetLocInfo( loc_code )
    if ( nRet ~= 0 ) then 
        err_msg = '获取站台货位信息失败! '..loc_code 
        goto set_state_ret
    end  
 
    if ( wave_no == '' ) then
        err_msg = '出库波次编码不能为空!' 
        goto set_state_ret
    end  
    if ( wh_code == '' ) then
        err_msg = '出库波次中仓库编码不能为空!' 
        goto set_state_ret
    end  
 
    -- 获取 出库波次 的出库单组成,生成一个 oo_no_set 对象,["OW01","OW02",...]
    strCondition = "S_WAVE_NO = '"..wave_no.."'"
    nRet, data_objs = m3.QueryDataObject(strLuaDEID, "OW_Compose", strCondition, "S_OO_NO" )
    if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objs end
    if ( data_objs == '' ) then 
        -- 设置错误信息
        err_msg = "波次号'"..wave_no.."'的出库波次没有组成对象!"
        goto set_state_ret
    end
    for n = 1, #data_objs do
        ow_compose = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
        table.insert( oo_no_set, ow_compose.S_OO_NO )
    end
 
    -- 【step1】 系统自动配货算法
    -- wms_out.Distribution_Procedure 是汉和WMS的一个标准的配盘算法
    -- MDF BY WHB 20250110 area_code 改成空(原因是可以在输送线上获取容器,否则就只能是存储区匹配)
    local distribution_parameter = {
        wh_code = wh_code, area_code = '', 
        exit_loc = exit_loc,
        bs_type = "Outbound_Wave",
        bs_no = wave_no,
        factory = out_wave.factory or '',
        station = station
        cntr_out_op_def = parameter.cntr_out_op_def or '',
        cntr_back_op_def = parameter.cntr_back_op_def or '',             
    }
 
    nRet, strRetInfo = wms_out.Distribution_Procedure( strLuaDEID, distribution_parameter, d_cntr_list, d_cntr_detail_list, shortage_list )  
    if ( nRet ~= 0 ) then
        err_msg = "【step1】系统自动配货算法,详细信息见日志!"..strRetInfo
        goto set_state_ret
    end
    
    -- V2.0
    -- 配盘明细根据料格合并相同货品数量
    nRet, d_cntr_detail_list = combine_cntr_detail( d_cntr_detail_list )
    if ( nRet ~= 0 ) then
        err_msg = "【step1.2】合并配盘明细错误!"..d_cntr_detail_list
        lua.Debug( strLuaDEID, debug.getinfo(1), "【step1.2】合并配盘明细错误", d_cntr_detail_list )
        goto set_state_ret
    end
 
    --【step2】 如果采用波次需要把【配盘明细】根据出库单明细进行批分
    -- 因为是采用波次出库,在生成配盘明细的 bs_type 的时候用的是 波次及波次号,在后面需要进一批批分到出库单上
    -- 如果没采用波次可以直接用 d_cntr_detail_list 生成数据
 
    -- step2.1 获取 出库单明细全部,如果有多个出库单把这些出库单的明细全部加在 outbound_detail_list
    nRet, outbound_detail_list = wms_out.Get_Outbound_Detail_list( strLuaDEID, oo_no_set )
    if ( nRet ~= 0 ) then
        err_msg = "【step2.1】获取所有出库单明细时出错,详细信息见日志!"
        goto set_state_ret
    end
    -- step 2.2 批分出库单明细
    d_cntr_detail_list = wms_out.Split_Distribution_CNTR_Detail( strLuaDEID, wave_no, "Outbound_Wave", d_cntr_detail_list, outbound_detail_list )
    lua.Debug( strLuaDEID, debug.getinfo(1), "配盘明细2 --> ", d_cntr_detail_list ) 
    
    -- step 2.3 检查出库单中的拣料箱数量,如果大于1的要根据拣料箱进行批分(明确这些拣料箱放哪些检出的货品)
    -- HAN 20241031 新增变更
    -- 找出波次中拣料箱数量大于1的出库单,这些出库单需要对拣货箱进行批分
    strCondition = "S_WAVE_NO = '"..wave_no.."'"
    nRet, data_objs = m3.QueryDataObject(strLuaDEID, "Outbound_Order", strCondition, "S_NO" )
    if (nRet ~= 0) then 
        err_msg =  "QueryDataObject失败!" 
        goto set_state_ret
    end
 
    for n = 1, #data_objs do
        oo_obj_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
        pick_box_num = lua.Get_NumAttrValue( oo_obj_attrs.N_PICKING_BOX_NUM )
        pick_box_code = lua.Get_StrAttrValue( oo_obj_attrs.S_PICK_BOX_CODE )
        if (pick_box_code == '' or pick_box_num == 0 ) then
            err_msg = "出库单'"..oo_obj_attrs.S_NO.."'没有绑定拣料箱!"
            goto set_state_ret
        end
        -- 从 d_cntr_detail_list 获取该出库单号的【配盘明细】
        sub_d_cntr_detail_list = get_d_cntr_detail_by_bs_no( d_cntr_detail_list, oo_obj_attrs.S_NO )
        if ( pick_box_num == 1 ) then
            -- 把拣料箱编码加入 d_cntr_detail
            for m = 1, #sub_d_cntr_detail_list do
                sub_d_cntr_detail_list[m].pick_box_code = pick_box_code
                table.insert( new_d_cntr_detail_list, sub_d_cntr_detail_list[m] )
            end
        else
            nRet, strRetInfo = wms_out.Split_CD_Detial_ByPickingBox( strLuaDEID, sub_d_cntr_detail_list, pick_box_code, new_d_cntr_detail_list )
            if ( nRet ~= 0 ) then
                err_msg = "出库单'"..oo_obj_attrs.S_NO.."'在批分拣料箱时发生错误, 具体信息请见日志!"
                lua.Debug( strLuaDEID, debug.getinfo(1), "【step2.3】 批分拣料箱时出错", "split_by_picking_box 返回错误: "..strRetInfo )
                goto set_state_ret                
            end
        end
    end    
 
    --【step3】 创建配盘及配盘明细
    nRet, strRetInfo = wms_out.Creat_Distribution_list( strLuaDEID, d_cntr_list, new_d_cntr_detail_list  )
    if ( nRet ~= 0 ) then
        err_msg = "wms_out.Creat_Distribution_list 发生错误,具体信息请查看系统日志!"
        lua.Debug( strLuaDEID, debug.getinfo(1), "【step3】 创建配盘及配盘明细出错", "wms_out.Creat_Distribution_list 返回错误: "..strRetInfo )
        goto set_state_ret      
    end
 
    -- 设置出库波次的状态
    ::set_state_ret::
    strCondition = "S_WAVE_NO = '"..wave_no.."'"
    local strSetAttr
 
    if ( err_msg ~= '' ) then
        -- 5 错误
        strSetAttr = "N_B_STATE = 5, S_ERR_MSG = '"..lua.FormatSQLString(err_msg).."', N_PRE_B_STATE = "..b_state
    else
        -- 2 配货完成
        strSetAttr = "N_B_STATE = 2, S_ERR_MSG = ''"
    end
    nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Outbound_Wave", strCondition, strSetAttr )
    if ( nRet ~= 0 ) then  lua.Error( strLuaDEID, debug.getinfo(1), "更新【出库波次】信息失败!"..strRetInfo ) end 
 
    if ( err_msg ~= '' ) then 
        mobox.addProcSQL3("Outbound_Wave", strCondition, strSetAttr)
        lua.Stop( strLuaDEID, "自动配盘失败!"..err_msg )
        return
    end
    -- 设置出库单状态 = 2 (配货完成)
    if ( err_msg == '' ) then
        strSetAttr = "N_B_STATE = 2"
        nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Outbound_Order", strCondition, strSetAttr )
        if ( nRet ~= 0 ) then  lua.Error( strLuaDEID, debug.getinfo(1), "更新【出库单】信息失败!"..strRetInfo ) end 
 
        -- 触发后台脚本生成出库作业
        local strCurEditClsID, strCurEditObjID
        nRet, strCurEditClsID, strCurEditObjID = mobox.getCurEditDataObjID( strLuaDEID )
        if ( nRet ~= 0 )  then lua.Error( strLuaDEID, debug.getinfo(1), "getCurEditDataObjID失败! " ) end      
        local add_wfp = {
            wfp_type = 1,
            cls = "Outbound_Wave",
            obj_id = strCurEditObjID,
            obj_name = "出库波次'"..wave_no.."'-->生成出库作业",
            trigger_event = "后台创建出库作业"
        }
        nRet, strRetInfo = m3.AddSysWFP( strLuaDEID, add_wfp )
        if ( nRet ~= 0 ) then 
            lua.Error( strLuaDEID, debug.getinfo(1), "AddSysWFP失败!"..strRetInfo )  
        end             
    end
end