--[[
|
编码: 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
|