--[[
|
编码:
|
名称: 预分配料箱算法
|
作者:HAN
|
日期:2024-8-5
|
|
来源:巨星料箱库
|
|
算法标识 CBG -- Compatible Bin Grid 专指WMS中与物料存储适配的料格系统
|
料格可以装载货品数量通过体积和料格体积或,重量和料箱的最大载重进行计算得到
|
算法特点:
|
-- 尽量有大一些的料格装更多的货品,减少入库任务条数(提高入库操作效率)
|
|
函数:
|
|
-- Release_Pre_Alloc_Cntr 释放预分配料箱
|
-- Pre_Alloc_Cntr_CBG 预分配料箱算法
|
|
|
功能:
|
空料箱呼出算法,货物可以适配多种类型料箱,根据入库的总体积进行计算
|
|
更改记录:
|
V2.0 HAN 20241220 对升格进行提前处理,加了一个专门的升格链表
|
|
-------------------------------------------------------------------------------------------------------------------------
|
几个主要数据类型定义
|
1) item_list -- 入库货品清单
|
{
|
item_code -- SKU编码
|
volume -- 单个体积
|
weight -- 单个重量
|
item_name,
|
cell_type:"A/B/C/D/E" -- 货品最小适配料格类型
|
qty -- 计划入库数量
|
alloc_qty -- 已经安排料箱的货品数量
|
cntr_cell_list -- 已经配货的料格 { cntr_code:"", cell_no:"", item_code:"xx", item_name:"", entry_batch_no:"SN01",
|
weight, volume, qty:10 ,sum_volume:10, sum_weigt:10}
|
|
empty_cell_type -- Q 数量的空料格类型 辅助用,表示本次整体呼出的空料箱类型
|
Q -- 需要呼出空料格数量
|
}
|
2) supplement_cntr_list -- 补料呼出的料箱
|
{
|
cntr_code:"xxx"
|
cell_type:"A/B/C/D/E"
|
cntr_good_weight: 100 -- 容器中货品重量
|
full: false/true,
|
empty_cell_num: 0,
|
empty_cell_list:[{"cell_no",item_code, item_name}] -- 呼出的补料料箱中的空料格 cell 属性同下面的 cell_list
|
cell_list:{
|
{ cntr_code:"", cell_no:"", item_code:"xx", item_name:"", entry_batch_no:"SN01", weight, volume, qty:10 ,sum_volume:10, sum_weigt:10}
|
}
|
}
|
3) out_cntr_list -- 呼出的空料箱( 和 supplement_cntr_list 是一样的)
|
{
|
cntr_code = "XXX",
|
cell_type = "A/B/C/D/E",
|
cntr_good_weight = 0,
|
full = false,
|
empty_cell_num = 0,
|
empty_cell_list:[{"cell_no",item_code, item_name}]
|
cell_list:{ -- 分配货品的料格
|
{ cntr_code:"", cell_no:"", item_code:"xx", item_name:"", entry_batch_no:"SN01", weight, volume, qty:10 ,sum_volume:10, sum_weigt:10}
|
}
|
}
|
变更记录:
|
V2.0 HAN 20241030
|
-- 取消给容器加锁
|
V3.0 HAN 20241104
|
-- 升格这里的处理有改进
|
V4.0 HAN 20241108
|
-- 补料呼出料箱和空料箱进行检查,相同料箱号的合并
|
]]
|
|
prj_base = require( "prj_base" )
|
wms_cntr = require( "wms_container" )
|
|
-- wms_pac_dmg 是制定料箱类型的精准预分配方法,属于 pre-alloction container 的一种,先require
|
local wms_pac = require( "wms_pac_dmg" )
|
|
-- 释放预分配的料格数量
|
function wms_pac.Release_Pre_Alloc_Cntr( strLuaDEID, bs_type, bs_no )
|
local nRet, strRetInfo
|
local data_objs
|
|
if lua.StrIsEmpty( bs_type ) then
|
return 1, "Release_Pre_Alloc_Cntr 函数中 bs_type 必须有值"
|
end
|
if lua.StrIsEmpty( bs_no ) then
|
return 1, "Release_Pre_Alloc_Cntr 函数中 bs_no 必须有值"
|
end
|
-- 释放预分配的料格数量
|
local strCondition = "S_BS_TYPE = '"..bs_type.."' AND S_BS_NO = '"..bs_no.."'"
|
nRet, data_objs = m3.QueryDataObject(strLuaDEID, "Pre_Alloc_CNTR_Detail", strCondition, "S_CNTR_CODE" )
|
if (nRet ~= 0) then
|
lua.Stop( strLuaDEID, "QueryDataObject失败!"..data_objs )
|
return
|
end
|
|
if ( data_objs ~= '' ) then
|
local n, m
|
local pac_detail
|
local cntr_list = {}
|
local find
|
for n = 1, #data_objs do
|
pac_detail = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
|
find = false
|
local cell = { cell_no = pac_detail.S_CELL_NO }
|
for m = 1, #cntr_list do
|
if ( cntr_list[m].cntr_code == pac_detail.S_CNTR_CODE ) then
|
find = true
|
table.insert( cntr_list[m].cell_list, cell )
|
break
|
end
|
end
|
if ( find == false ) then
|
local cntr = {
|
cntr_code = pac_detail.S_CNTR_CODE,
|
cell_list = {}
|
}
|
table.insert( cntr.cell_list, cell )
|
table.insert( cntr_list, cntr )
|
end
|
end
|
|
local cell_num
|
for m = 1, #cntr_list do
|
strCondition = "S_CODE = '"..cntr_list[m].cntr_code.."'"
|
cell_num = #cntr_list[m].cell_list
|
nRet, strRetInfo = mobox.decDataObjAccQty( strLuaDEID, "Container", strCondition, "N_ALLOC_CELL_NUM", cell_num )
|
if ( nRet ~= 0 ) then
|
lua.Stop( strLuaDEID, "decDataObjAccQty(Container)失败! "..strRetInfo )
|
return
|
end
|
end
|
|
-- 把料格状态=3(预约)的设置为 0
|
strUpdateSql = "N_EMPTY_FULL = 0, S_ALLOC_OP_CODE = ''"
|
strCondition = "N_EMPTY_FULL = 3 AND S_ALLOC_OP_CODE = '"..bs_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container_Cell", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then
|
lua.Stop( strLuaDEID, "更新【Container_Cell】状态信息失败!"..strRetInfo )
|
return
|
end
|
end
|
return 0
|
end
|
|
-- item list 排序函数 把体积大的排前面
|
local function item_sort_volume( item_a, item_b )
|
return item_a.volume > item_b.volume
|
end
|
|
-- 根据货品体积计算需要多少个 料格, 料格体积 box_volume
|
-- item_volume 货品单个体积
|
-- 返回参数1 -- 料格数量 2 -- 可装货品数量 3 -- 错误标记非0为越界
|
local function calculate_box_count_by_volume(box_volume, item_volume, qty )
|
|
if ( 0 == item_volume or 0 == box_volume ) then return 0,0 end
|
local items_per_box = math.floor( box_volume / item_volume )
|
|
-- 单品就超体积,这种情况一般是数据错误
|
if ( items_per_box == 0 ) then return 0,0 end
|
|
local num_boxes = math.floor( qty / items_per_box)
|
return num_boxes, num_boxes*items_per_box
|
end
|
|
-- 返回需要多少个料格,及装载的货品数量
|
-- 返回参数1 -- 料格数量 2 -- 可装货品数量 3 -- 错误标记非0为越界
|
local function calculate_box_count_by_weight( pac_cfg, cell_type_index, item_weight, qty )
|
if ( 0 == item_weight ) then return 0,0 end
|
local items_per_box = math.floor( pac_cfg.ctd.load_capacity / item_weight )
|
|
-- 单品就超重,这种情况一般是数据错误
|
if ( items_per_box == 0 ) then return 0,0 end
|
|
local num_boxes = math.floor( qty / items_per_box)
|
return num_boxes*pac_cfg.ctd.grid_box_def[cell_type_index].box_num, items_per_box*num_boxes
|
end
|
|
-- 计算出item中的 Qa/Qb/Qc/Qd/Qe 数量
|
-- grid_def {cell_type="A",box_num = 1, volume = 72000 }
|
local function generate_item_needemptycell_qty( strLuaDEID, ctd, item_list, grid_def )
|
local nRet, strRetInfo, n
|
|
local qty, total_volume, volumeX, pk_qty, qX
|
local cell_volume = grid_def.volume or 0
|
local box_num = grid_def.box_num or 0
|
if box_num <= 0 then
|
return 1,"料箱类型定义中料格定义不合规! box_num 必须大于0"
|
end
|
|
local cntr_max_weight = ctd.load_capacity or 0
|
local cell_weight = cntr_max_weight/grid_def.box_num
|
local cell_type = grid_def.cell_type
|
local sum_Q = 0
|
local loading_limit
|
|
if ( cell_volume == nil or cell_volume <= 0 ) then
|
return 1,"料箱类型定义中料格定义不合规! 料格体积必须大于0"
|
end
|
|
for n = 1, #item_list do
|
-- MDY BY HAN 20241211 如果当前进行匹配的料格类型 大于 货品的最小适配料格(A,B,C,D,E),不做判断
|
if ( cell_type > item_list[n].S_CELL_TYPE ) then goto continue end
|
|
item_list[n].empty_cell_type = cell_type -- 当前呼出的料箱规格
|
item_list[n].Q = 0 -- cell_type 类型的料格数量
|
|
if (item_list[n].qty > item_list[n].alloc_qty ) then
|
|
qty = item_list[n].qty - item_list[n].alloc_qty
|
if ( lua.equation( qty, 0 ) ) then goto continue end
|
|
-- 根据容器定义中的计数方法进行判断 Mixed 为混合模式,会从根据情况从体积计算变成重量计算
|
if ctd.count_method == "Mixed" or ctd.count_method == "Volume" then
|
-- *** 注意这里还留下一个问题,就是重量是否会超,可能要对 calculate_box_count_by_volume 优化一下
|
total_volume = qty*item_list[n].volume
|
pk_qty = 0
|
if ( total_volume > cell_volume ) then
|
item_list[n].Q, pk_qty = calculate_box_count_by_volume( cell_volume, item_list[n].volume, qty )
|
volumeX = (item_list[n].volume)*(qty-pk_qty)
|
else
|
volumeX = total_volume
|
end
|
|
-- 如果整除后还有余数, 判断这些体积是否增加一个料格
|
if ( volumeX > 0 ) then
|
-- 如果料格在料箱中最小的料格说明不能再降格了
|
if (item_list[n].S_CELL_TYPE == cell_type or grid_def.is_smallest ) then
|
item_list[n].Q = item_list[n].Q + 1
|
else
|
-- 2024-9-28 改进
|
-- 如果剩余体积 > 降格后料格体积 Q需要加1
|
nRet, next_grid_def = wms_cntr.Get_CTD_Next_GridDef( ctd, cell_type )
|
if nRet ~= 0 then
|
return 1, "wms_cntr.Get_CTD_Next_GridDef 失败!"..next_grid_def
|
end
|
if ( volumeX > next_grid_def.volume ) then
|
item_list[n].Q = item_list[n].Q + 1
|
end
|
end
|
end
|
elseif ctd.count_method == "Limit" then
|
-- 获取 SKU 在 grid_def.cell_type 的料格中的装载数量
|
nRet, loading_limit = wms_base.GetSKU_LoadingLimit( item_list[n], ctd.ctd_code, grid_def.cell_type )
|
if nRet ~= 0 then
|
return 1, loading_limit
|
end
|
-- qX 为余数
|
if qty >= loading_limit then
|
item_list[n].Q = math.floor(qty/loading_limit)
|
qX = qty - item_list[n].Q*loading_limit
|
else
|
qX = qty
|
end
|
if qX > 0 then
|
-- 如果料格在料箱中最小的料格说明不能再降格了
|
if (item_list[n].S_CELL_TYPE == cell_type or grid_def.is_smallest ) then
|
item_list[n].Q = item_list[n].Q + 1
|
else
|
-- 如果剩余体积 > 降格后料格数量
|
nRet, next_grid_def = wms_cntr.Get_CTD_Next_GridDef( ctd, cell_type )
|
if nRet ~= 0 then
|
return 1, "wms_cntr.Get_CTD_Next_GridDef 失败!"..next_grid_def
|
end
|
|
nRet, loading_limit = wms_base.GetSKU_LoadingLimit( item_list[n], ctd.ctd_code, next_grid_def.cell_type )
|
if nRet ~= 0 then
|
return 1, loading_limit
|
end
|
if ( qX > loading_limit ) then
|
item_list[n].Q = item_list[n].Q + 1
|
end
|
end
|
end
|
else
|
return 1, "料箱计数方法 = '"..ctd.count_method.."'的算法还没实现!"
|
end
|
-- 计算呼出料格总数
|
sum_Q = sum_Q + item_list[n].Q
|
end
|
::continue::
|
end
|
return 0, sum_Q
|
end
|
|
-- 检查 item_list 中的item是否有物料的最低适配货隔 == cell_type 并且还有量没分配料格的,如果有说明该类型的料格缺少
|
-- 如果有货品必须要cell_type类型料箱,返回 true, 并且返回是item_list中的货品下标
|
local function have_this_cell_type( item_list, cell_type )
|
local n
|
|
for n = 1, #item_list do
|
if ( item_list[n].ok == false and item_list[n].S_CELL_TYPE == cell_type ) then
|
if ( item_list[n].qty > item_list[n].alloc_qty ) then
|
if ( lua.equation( item_list[n].qty, item_list[n].alloc_qty ) == false ) then
|
return true, n
|
end
|
end
|
end
|
end
|
return false, 0
|
end
|
|
-- 把空料格数量小的排前面
|
local function empty_cntr_sort( item_a, item_b )
|
return item_a.empty_cell_num < item_b.empty_cell_num
|
end
|
|
local function cntr_in_this_list( cntr_code, out_cntr_result )
|
if ( nil == out_cntr_result ) then return false end
|
local n
|
|
for n = 1, #out_cntr_result do
|
if ( out_cntr_result[n].cntr_code == cntr_code ) then return true end
|
end
|
return false
|
end
|
|
--[[ ***
|
呼出 cell_need_num 个 cell_type 类型的空料格,需要多少个料箱
|
从数据库查询获取 料箱类型 = cell_type 有空料格的料箱列表,并且根据空料格数量的大小进行排序,空料格数量大的在最前面
|
|
输入参数:
|
pac_cfg -- 预分配配置参数
|
cell_type 呼出料箱类型
|
cell_need_num 需要呼出多少个料格
|
|
out_cntr_list 呼出料箱列表, 是本函数计算后的主要成果
|
query_cntr_list -- 除 out_cntr_list 外可用的料箱,用于 out_cntr_list 在分配货物是因为重量的原因不能使用需要分配新的料箱
|
out_cntr_result -- 已经呼出的料箱
|
|
返回3个参数,格式(nRet,x_sum_Q, strErrInfo )
|
nRet 0 正常 1 -- 无法匹配需求 2 -- 程序错误
|
x_sum_Q 呼出的料格缺少的cell_type类型的料格数量
|
]]
|
local function generate_out_cntr_list( strLuaDEID, pac_cfg, cell_type, cell_need_num, out_cntr_list, query_cntr_list, out_cntr_result )
|
local nRet, strRetInfo, strCondition, strOrder, n
|
|
-- 输入参数判断
|
if ( pac_cfg.wh_code == nil or pac_cfg.wh_code == '' ) then
|
return 1, 0, "输入参数错误, wh_code必须有值"
|
end
|
local str_loc_where = "S_WH_CODE = '"..pac_cfg.wh_code.."'"
|
if ( pac_cfg.area_code ~= nil and pac_cfg.area_code ~= '') then
|
str_loc_where = str_loc_where.." AND S_AREA_CODE = '"..pac_cfg.area_code.."'"
|
end
|
|
if ( pac_cfg.aisle ~= nil and pac_cfg.aisle ~= '') then
|
str_loc_where = str_loc_where.." AND S_AISLE_CODE IN ("..pac_cfg.aisle..")"
|
end
|
local cntr_max_weight = pac_cfg.ctd.load_capacity
|
local cntr_condition = " S_CTD_CODE = '"..pac_cfg.ctd.ctd_code.."'"
|
|
-- N_EMPTY_FULL < 2 料箱未满
|
strCondition = "N_EMPTY_CELL_NUM > N_ALLOC_CELL_NUM AND S_SPEC = '"..cell_type.."' AND N_LOCK_STATE = 0 AND C_ENABLE = 'Y' AND "..cntr_condition.." AND N_EMPTY_FULL < 2 AND N_EMPTY_CELL_NUM > 0 "..
|
" AND S_CODE IN (select S_CNTR_CODE from TN_Loc_Container with (NOLOCK) where S_LOC_CODE IN (select S_CODE from TN_Location with (NOLOCK) where "..str_loc_where..")) "
|
if pac_cfg.ctd.check_capacity then
|
if cntr_max_weight <= 0 then
|
return 1, "容器类型定义'"..pac_cfg.ctd.ctd_code.."'中缺少容器载重参数!"
|
end
|
strCondition = strCondition.." AND F_GOOD_WEIGHT < "..cntr_max_weight
|
end
|
|
strOrder = "(N_EMPTY_CELL_NUM - N_ALLOC_CELL_NUM) desc"
|
|
local cntr_objs, cntr_attr
|
nRet, cntr_objs = m3.QueryDataObject(strLuaDEID, "Container", strCondition, strOrder )
|
if nRet ~= 0 then return 2, 0, cntr_objs end
|
if cntr_objs == '' then
|
return 0, cell_need_num, "没找到匹配的料箱"
|
end
|
|
local empty_cell_num, qty
|
local empty_cntr_list = {}
|
local query_cntr_count = 0 -- 这样的箱子不需要太多不超过100
|
|
query_cntr_list = {} -- 查询出来的符合条件的料箱
|
|
for n = 1, #cntr_objs do
|
cntr_attr = m3.KeyValueAttrsToObjAttr(cntr_objs[n].attrs)
|
-- 防止找到的料箱已经在呼出的料箱列表中
|
if ( cntr_in_this_list( cntr_attr.S_CODE, out_cntr_result ) ) then goto continue end
|
|
if ( cell_need_num > 0 ) then
|
-- 呼出料箱空料格数量
|
empty_cell_num = lua.StrToNumber( cntr_attr.N_EMPTY_CELL_NUM ) - lua.StrToNumber( cntr_attr.N_ALLOC_CELL_NUM )
|
if ( cell_need_num > empty_cell_num ) then
|
qty = empty_cell_num
|
else
|
-- 特别关注: 需要找到最适配的料箱 cell_need_num = empty_cell_num 是最优的
|
if ( cell_need_num == empty_cell_num ) then
|
qty = cell_need_num
|
else
|
-- 把当前这个料箱加到附加链表, 没找到最优数量的料格后会从这个 empty_cntr_list 里获取
|
local empty_cntr = {
|
cntr_code = cntr_attr.S_CODE,
|
cntr_good_weight = lua.StrToNumber( cntr_attr.F_GOOD_WEIGHT ),
|
empty_cell_num = empty_cell_num
|
}
|
table.insert( empty_cntr_list, empty_cntr )
|
goto continue
|
end
|
end
|
|
-- 分配成功, 把这个料箱加入呼出料箱列表
|
local out_cntr = {
|
cntr_code = cntr_attr.S_CODE,
|
cntr_good_weight = lua.StrToNumber( cntr_attr.F_GOOD_WEIGHT ),
|
cell_type = cell_type,
|
empty_cell_list = {},
|
full = false,
|
cell_list = {}
|
}
|
table.insert( out_cntr_list, out_cntr )
|
cell_need_num = cell_need_num - qty
|
else
|
-- query_cntr_list 是候补
|
local out_cntr = {
|
cntr_code = cntr_attr.S_CODE,
|
cntr_good_weight = lua.StrToNumber( cntr_attr.F_GOOD_WEIGHT ),
|
cell_type = cell_type,
|
empty_cell_list = {},
|
full = false,
|
cell_list = {}
|
}
|
table.insert( query_cntr_list, out_cntr )
|
query_cntr_count = query_cntr_count + 1
|
if ( query_cntr_count > 100 ) then break end
|
end
|
|
::continue::
|
end
|
|
-- 如果还有 cell_need_num 没分配, 从上面为了适配料格数量跳过的哪些料格
|
if ( cell_need_num > 0 and #empty_cntr_list > 0 ) then
|
table.sort( empty_cntr_list, empty_cntr_sort )
|
-- 取第一个空料箱(这个是空料箱数最接近cell_need_num)
|
local out_cntr = {
|
cntr_code = empty_cntr_list[1].cntr_code,
|
cntr_good_weight = empty_cntr_list[1].cntr_good_weight,
|
cell_type = cell_type,
|
empty_cell_list = {},
|
full = false,
|
cell_list = {}
|
}
|
table.insert( out_cntr_list, out_cntr )
|
|
for n = 2, #empty_cntr_list do
|
if ( query_cntr_count > 100 ) then break end
|
local out_cntr = {
|
cntr_code = empty_cntr_list[n].cntr_code,
|
cntr_good_weight = empty_cntr_list[n].cntr_good_weight,
|
cell_type = cell_type,
|
empty_cell_list = {},
|
full = false,
|
cell_list = {}
|
}
|
table.insert( query_cntr_list, out_cntr )
|
query_cntr_count = query_cntr_count + 1
|
end
|
cell_need_num = 0
|
end
|
return 0, cell_need_num
|
end
|
|
-- 在呼出的空料箱里分配货物, 遍历 item_list 把item_list的货品批分到 呼出的空料箱中,空料箱资源是 out_cntr_list
|
local function distribute_to_outcntrlist( strLuaDEID, pac_cfg, item_list, out_cntr_list, cell_type )
|
local nRet, strRetInfo, nCount, n, m, qty, si_qty, i
|
local sum_Q = 0 -- 补料料箱里批分掉的Q
|
local empty_cell_count
|
|
nCount = #item_list
|
if ( nCount == 0 ) then return 0 end
|
-- m 是呼出的料箱列表下标
|
for m = 1, #out_cntr_list do
|
empty_cell_count = lua.GetTableCount( out_cntr_list[m].empty_cell_list )
|
if ( empty_cell_count > 0 ) then
|
-- 遍历item_list n 是货品列表下标
|
for n = 1, nCount do
|
-- > 0 说明有cell_type类型的料箱格需求
|
if ( item_list[n].ok == false and item_list[n].Q > 0 and item_list[n].empty_cell_type == cell_type ) then
|
-- 遍历呼出的空料箱里的空料格
|
for i = 1, empty_cell_count do
|
if ( out_cntr_list[m].empty_cell_list[i].item_code == '' ) then
|
-- 取一个空料格存储计算能存储多少个货品
|
local cntr_cell = {}
|
cntr_cell.cntr_code = out_cntr_list[m].cntr_code
|
cntr_cell.cell_no = out_cntr_list[m].empty_cell_list[i].cell_no
|
cntr_cell.good_volume = 0 -- 是空料格
|
cntr_cell.cell_type = cell_type
|
nRet, si_qty = wms_cntr.Get_CntrCell_Goods_Qty( pac_cfg.ctd, out_cntr_list[m].cntr_good_weight, cntr_cell, item_list[n] )
|
if ( nRet ~= 0 ) then
|
return 1, si_qty
|
end
|
|
qty = item_list[n].qty - item_list[n].alloc_qty
|
if ( si_qty > qty ) then si_qty = qty end
|
-- 呼出料箱里加一个料格存储 item
|
if ( si_qty > 0 ) then
|
-- 生成批次号
|
nRet, strSN = prj_base.Generate_Batch_No( item_list[n].S_ITEM_CODE )
|
if ( nRet ~= 0 ) then return 1, strSN end
|
|
item_list[n].alloc_qty = item_list[n].alloc_qty + si_qty
|
if ( lua.equation( item_list[n].alloc_qty, item_list[n].qty ) ) then
|
item_list[n].ok = true
|
end
|
|
-- 把分配掉的si_qty个货品加到呼出的空料格里
|
local cell_item = {
|
cntr_code = cntr_cell.cntr_code,
|
cell_type = cntr_cell.cell_type,
|
cell_no = cntr_cell.cell_no,
|
item_code = item_list[n].S_ITEM_CODE,
|
item_name = item_list[n].S_ITEM_NAME,
|
row = item_list[n].row,
|
entry_batch_no = strSN,
|
qty = si_qty,
|
sum_volume = si_qty*item_list[n].volume,
|
sum_weight = si_qty*item_list[n].weight,
|
weight = item_list[n].weight,
|
volume = item_list[n].volume,
|
sku = item_list[n]
|
}
|
table.insert( out_cntr_list[m].cell_list, cell_item )
|
|
-- 20241104 容器料格分配数量+1,料格设置为预分配
|
nRet, strRetInfo = wms_cntr.CNTR_cell_alloc_set( strLuaDEID, cntr_cell.cntr_code, cntr_cell.cell_no, pac_cfg.bs_no )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
-- 容器中商品的总重量需要加上刚加入到料格里的货品重量
|
out_cntr_list[m].cntr_good_weight = out_cntr_list[m].cntr_good_weight + cell_item.sum_weight
|
table.insert( item_list[n].cntr_cell_list, cell_item )
|
-- empty_cell_list 里item_code 设置为有值,表示这个空料格已经有货
|
out_cntr_list[m].empty_cell_list[i].item_code = item_list[n].S_ITEM_CODE
|
out_cntr_list[m].empty_cell_list[i].item_name = item_list[n].S_ITEM_NAME
|
item_list[n].Q = item_list[n].Q - 1
|
end
|
end
|
if ( item_list[n].Q <= 0 ) then
|
break
|
end
|
end
|
end
|
end
|
end
|
end
|
|
return 0
|
end
|
|
local function item_sort_by_cell_tye( item_a, item_b )
|
return item_a.S_CELL_TYPE < item_b.S_CELL_TYPE
|
end
|
|
-- 删除呼出容器中的empty_cell 列表中 名为 cell_no 的料格
|
local function remove_empty_cell( cntr, cell_no )
|
local n
|
for n = 1, #cntr.empty_cell_list do
|
if (cntr.empty_cell_list[n].cell_no == cell_no ) then
|
table.remove( cntr.empty_cell_list, n )
|
return
|
end
|
end
|
end
|
|
-- 把料箱中已经分配了item的空料格删除
|
local function remove_empty_cell_have_item_code( cntr )
|
-- 清除料箱里的空容器列表
|
local m = 1
|
while cntr.empty_cell_list[m] do
|
if (cntr.empty_cell_list[m].item_code ~= '' ) then
|
table.remove( cntr.empty_cell_list, m )
|
else
|
m = m + 1
|
end
|
end
|
end
|
|
-- 把一个指定的货品批分到 呼出容器列表 中, 如果 out_cntr_list 批分不完,从 query_cntr_list 里继续批分
|
local function distribute_item_to_out_cntr_list( strLuaDEID, pac_cfg, item, out_cntr_list )
|
local nRet, strRetInfo, nCount, n, m, qty, si_qty, i
|
local empty_cell_count
|
|
if ( item.ok ) then return end
|
for m = 1, #out_cntr_list do
|
-- 遍历呼出的空料箱里的空料格
|
for i = 1, #out_cntr_list[m].empty_cell_list do
|
if ( out_cntr_list[m].empty_cell_list[i].item_code == '' ) then
|
-- 取一个空料格存储计算能存储多少个货品
|
local cntr_cell = {}
|
cntr_cell.cntr_code = out_cntr_list[m].cntr_code
|
cntr_cell.cell_no = out_cntr_list[m].empty_cell_list[i].cell_no
|
cntr_cell.good_volume = 0 -- 是空料格
|
cntr_cell.cell_type = out_cntr_list[m].cell_type
|
nRet, si_qty = wms_cntr.Get_CntrCell_Goods_Qty( pac_cfg.ctd, out_cntr_list[m].cntr_good_weight, cntr_cell, item )
|
if ( nRet ~= 0 ) then
|
return 1, si_qty
|
end
|
|
qty = item.qty - item.alloc_qty
|
if ( si_qty > qty ) then
|
si_qty = qty
|
end
|
|
-- 呼出料箱里加一个料格存储 item
|
if ( si_qty > 0 ) then
|
-- 生成批次号
|
nRet, strSN = prj_base.Generate_Batch_No( item.S_ITEM_CODE )
|
if ( nRet ~= 0 ) then return 1, strSN end
|
|
item.alloc_qty = item.alloc_qty + si_qty
|
if ( lua.equation( item.alloc_qty, item.qty ) ) then item.ok = true end
|
|
-- 把分配掉的si_qty个货品加到呼出的空料格里
|
local cell_item = {
|
cntr_code = cntr_cell.cntr_code,
|
cell_type = cntr_cell.cell_type,
|
cell_no = cntr_cell.cell_no,
|
item_code = item.S_ITEM_CODE,
|
item_name = item.S_ITEM_NAME,
|
row = item.row,
|
entry_batch_no = strSN,
|
qty = si_qty,
|
sum_volume = si_qty*item.volume,
|
sum_weight = si_qty*item.weight,
|
weight = item.weight,
|
volume = item.volume,
|
sku = item
|
}
|
table.insert( out_cntr_list[m].cell_list, cell_item )
|
|
-- 容器料格分配数量+1,料格设置为预分配
|
nRet, strRetInfo = wms_cntr.CNTR_cell_alloc_set( strLuaDEID, cntr_cell.cntr_code, cntr_cell.cell_no, pac_cfg.bs_no )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
-- 容器中商品的总重量需要加上刚加入到料格里的货品重量
|
out_cntr_list[m].cntr_good_weight = out_cntr_list[m].cntr_good_weight + cell_item.sum_weight
|
table.insert( item.cntr_cell_list, cell_item )
|
-- empty_cell_list 里item_code 设置为有值,表示这个空料格已经有货
|
out_cntr_list[m].empty_cell_list[i].item_code = item.S_ITEM_CODE
|
out_cntr_list[m].empty_cell_list[i].item_name = item.S_ITEM_NAME
|
end
|
end
|
if ( item.ok ) then break end
|
end
|
remove_empty_cell_have_item_code( out_cntr_list[m] )
|
if ( item.ok ) then break end
|
end
|
|
return 0
|
end
|
|
-- 把一个料格加入呼出料箱列表
|
local function put_cell_item_to_out_cntr_list( out_cntr_list, cell_item )
|
local n
|
|
for n = 1, #out_cntr_list do
|
if ( out_cntr_list[n].cntr_code == cell_item.cntr_code ) then
|
table.insert( out_cntr_list[n].cell_list, cell_item )
|
-- 容器中商品的总重量需要加上岗加入到料格里的货品重量
|
out_cntr_list[n].cntr_good_weight = out_cntr_list[n].cntr_good_weight + cell_item.sum_weight
|
return
|
end
|
end
|
end
|
|
-- 从已经呼出的料箱列表中分配一个空的料格
|
-- out_cntr_list 已经呼出的料箱列表,cell_type 匹配的料格类型, item 分配的货品, need_q 需要的料格数量
|
local function alloc_cell_in_out_cntr_list( strLuaDEID, pac_cfg, out_cntr_list, cell_type, item, need_q )
|
local n, empty_cell_count
|
local alloc_item = false
|
local cntr_cell = {}
|
|
for n = 1, #out_cntr_list do
|
empty_cell_count = lua.GetTableCount( out_cntr_list[n].empty_cell_list )
|
alloc_item = false
|
if ( out_cntr_list[n].full == false and out_cntr_list[n].cell_type == cell_type and empty_cell_count > 0 ) then
|
for i = 1, empty_cell_count do
|
if ( out_cntr_list[n].empty_cell_list[i].item_code == '' ) then
|
-- 取一个空料格存储计算能存储多少个货品
|
cntr_cell.cntr_code = out_cntr_list[n].cntr_code
|
cntr_cell.cell_no = out_cntr_list[n].empty_cell_list[i].cell_no
|
cntr_cell.good_volume = 0 -- 是空料格
|
cntr_cell.cell_type = cell_type
|
nRet, si_qty = wms_cntr.Get_CntrCell_Goods_Qty( pac_cfg.ctd, out_cntr_list[n].cntr_good_weight, cntr_cell, item )
|
if ( nRet ~= 0 ) then
|
return 1, si_qty
|
end
|
|
-- 需要分配料格的数量 qty,如果计算出来的数量大于需求数量,就用需求数量
|
qty = item.qty - item.alloc_qty
|
if ( si_qty > qty ) then si_qty = qty end
|
|
-- 呼出料箱里加一个料格存储 item
|
if ( si_qty > 0 ) then
|
-- 生成批次号
|
nRet, strSN = prj_base.Generate_Batch_No( item.S_ITEM_CODE )
|
if ( nRet ~= 0 ) then return 1, strSN end
|
|
item.alloc_qty = item.alloc_qty + si_qty
|
if ( lua.equation( item.alloc_qty, item.qty ) ) then item.ok = true end
|
|
-- 把分配掉的si_qty个货品加到补料呼出的容器里
|
local cell_item = {
|
cntr_code = cntr_cell.cntr_code,
|
cell_type = cntr_cell.cell_type,
|
cell_no = cntr_cell.cell_no,
|
item_code = item.S_ITEM_CODE,
|
item_name = item.S_ITEM_NAME,
|
row = item.row,
|
entry_batch_no = strSN,
|
qty = si_qty,
|
sum_volume = si_qty*item.volume,
|
sum_weight = si_qty*item.weight,
|
weight = item.weight,
|
volume = item.volume,
|
sku = item
|
}
|
|
put_cell_item_to_out_cntr_list( out_cntr_list, cell_item )
|
table.insert( item.cntr_cell_list, cell_item )
|
|
-- 容器料格分配数量+1,料格设置为预分配
|
nRet, strRetInfo = wms_cntr.CNTR_cell_alloc_set( strLuaDEID, cntr_cell.cntr_code, cntr_cell.cell_no, pac_cfg.bs_no )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
-- empty_cell_list 里item_code 设置为有值,表示这个空料格已经有货
|
out_cntr_list[n].empty_cell_list[i].item_code = item.S_ITEM_CODE
|
out_cntr_list[n].empty_cell_list[i].item_name = item.S_ITEM_NAME
|
need_q = need_q - 1
|
alloc_item = true
|
if ( need_q == 0 ) then break end
|
end
|
end
|
end
|
end
|
|
-- 删除那些已经分配货品的空料格empty_cell
|
if ( alloc_item ) then
|
remove_empty_cell_have_item_code( out_cntr_list[n] )
|
end
|
if ( need_q == 0 ) then break end
|
end
|
return 0, need_q
|
end
|
|
-- 清除呼出料箱列表中没有cell_list的节点
|
local function remove_no_cell_list_out_cntr_list( out_cntr_list )
|
local n = 1
|
while out_cntr_list[n] do
|
if (#out_cntr_list[n].cell_list == 0 ) then
|
table.remove( out_cntr_list, n )
|
else
|
n = n + 1
|
end
|
end
|
end
|
|
--[[
|
step2 遍历SKU清单进行料箱预分配
|
输入参数:
|
pac_cfg -- 预分配算法基本参数配置
|
item_list -- 需要做预分配的货品明细
|
supplement_cntr_list 补料呼出的料箱列表
|
out_cntr_result -- 呼出的料箱列表
|
|
注意:料格类型A体积最大,依次类推
|
--]]
|
local function get_out_cntr_list_cbg( strLuaDEID, pac_cfg, item_list, supplement_cntr_list, out_cntr_result )
|
local nRet, strRetInfo
|
|
if pac_cfg.ctd.count_method == "Volume" then
|
-- 排序把体积大的放前面
|
table.sort( item_list, item_sort_volume )
|
end
|
|
-- 从A类型料箱开始一直到E类型料箱呼出空料箱(大宗货品用A料框来满足入库需求)
|
local sum_Q, cell_type_index, Qx, x_sum_Q
|
local out_cntr_list = {}
|
local cell_type
|
local b_have_this_cell_type = false
|
local item_index, n
|
local upgrad_item_list = {} -- 需要进行升格的物料
|
local query_cntr_list
|
|
-- 从A类型料格开始变量容器定义的料格类型
|
for cell_type_index, grid_def in ipairs( pac_cfg.ctd.grid_box_def ) do
|
cell_type = grid_def.cell_type
|
-- step1 获取某类型空料箱格数量
|
nRet, sum_Q = generate_item_needemptycell_qty( strLuaDEID, pac_cfg.ctd, item_list, grid_def, cntr_max_weight )
|
if ( nRet ~= 0 ) then
|
return nRet, sym_Q
|
end
|
|
if ( sum_Q > 0 ) then
|
--呼出空料箱格 生成 out_cntr_list
|
out_cntr_list = {}
|
query_cntr_list = {}
|
|
-- 呼出数量最匹配的空料箱, 返回 out_cntr_list [{"cnter":"","good_weight":10, cell_type:"B"}]
|
-- x_sum_Q 是不足的 cell_type 料格数量,需要进行降格
|
nRet, x_sum_Q, strRetInfo = generate_out_cntr_list( strLuaDEID, pac_cfg, cell_type, sum_Q, out_cntr_list, query_cntr_list )
|
if (nRet ~= 0 ) then
|
return 2, "generate_out_cntr_list 发生错误! "..strRetInfo
|
end
|
|
-- 存在呼出的料箱列表,把货品批分到呼出的料箱格
|
if ( lua.IsTableEmpty( out_cntr_list ) == false ) then
|
-- 设置 out_cntr_list 中 empty_cell_list
|
nRet, strRetInfo = wms_pac.set_out_cntr_empty_cell( strLuaDEID, out_cntr_list )
|
if nRet ~= 0 then
|
return 2, strRetInfo
|
end
|
-- 把 item_list 中的货品批分到 呼出的 out_cntr_list 中的容器中
|
nRet, strRetInfo = distribute_to_outcntrlist( strLuaDEID, pac_cfg, item_list, out_cntr_list, cell_type )
|
if ( nRet ~= 0 ) then
|
return 2, "step4.3 发生错误! "..strRetInfo
|
end
|
wms_pac.reset_empty_cell_info( out_cntr_list )
|
lua.table_merge( out_cntr_result, out_cntr_list )
|
end
|
if ( x_sum_Q > 0 ) then
|
-- 如果未分配料箱的货品中还存在 cell_type 的料格
|
b_have_this_cell_type, item_index = have_this_cell_type( item_list, cell_type )
|
if ( b_have_this_cell_type ) then
|
-- 如果不是A类型的料格需要考虑升格
|
if ( cell_type == 'A') then
|
local x_qty = item_list[item_index].qty - item_list[item_index].alloc_qty
|
return 1, "在分配货品编码 = '"..item_list[item_index].S_ITEM_CODE.."'时, 料箱类型 = "..cell_type.."的料箱不足! 货品数量 = "..x_qty
|
end
|
end
|
|
-- MDF 20241220
|
-- 说明没呼出足够的适配料箱
|
if ( cell_type_index == 1 ) then -- A 料格
|
-- 降格处理 A --> B
|
lua.Warning( strLuaDEID, debug.getinfo(1), pac_cfg.bs_type.."-->'"..pac_cfg.bs_no.."'有"..x_sum_Q.."个A料箱降格!" )
|
else
|
-- 升格处理 B --> A
|
lua.Warning( strLuaDEID, debug.getinfo(1), pac_cfg.bs_type.."-->'"..pac_cfg.bs_no.."'有"..x_sum_Q.."个"..cell_type.."料箱升格!" )
|
-- 把item_list中 item.Q > 0 的加入升格通道
|
n = 1
|
while item_list[n] do
|
if (item_list[n].Q > 0 ) then
|
item_list[n].upgrad_cell_index = cell_type_index
|
table.insert( upgrad_item_list, item_list[n] )
|
table.remove( item_list, n )
|
else
|
n = n + 1
|
end
|
end
|
end
|
end
|
-- MDF 20241220
|
-- 判断 item_list 中的数量是否已经全部分配到容器,如果全部分配了料箱 break
|
if ( wms_pac.item_list_is_all_ok( item_list ) or #item_list == 0 ) then
|
break
|
end
|
end
|
end
|
|
-- MDF 20241220 ***
|
-- step5 如果有升料格需求的货品进行升格处理
|
-- 如果有升料格的货品进入升格
|
local qty, total_volume, Q, cell_volume, pk_qty, xQty
|
for n = 1, #upgrad_item_list do
|
if ( upgrad_item_list[n].ok == false ) then
|
cell_type_index = upgrad_item_list[n].upgrad_cell_index
|
-- 升格循环
|
while ( cell_type_index > 1 ) do
|
cell_type_index = cell_type_index - 1 -- 升一个料格
|
cell_type = pac_cfg.ctd.grid_box_def[cell_type_index].cell_type
|
|
qty = upgrad_item_list[n].qty - upgrad_item_list[n].alloc_qty
|
|
if pac_cfg.ctd.count_method == "Mixed" or pac_cfg.ctd.count_method == "Volume" then
|
total_volume = qty*upgrad_item_list[n].volume
|
cell_volume = pac_cfg.ctd.grid_box_def[cell_type_index].volume
|
if ( total_volume > cell_volume ) then
|
--Q = math.floor( total_volume/cell_volume )
|
Q, pk_qty = calculate_box_count_by_volume( cell_volume, upgrad_item_list[n].volume, qty )
|
else
|
Q = 1
|
end
|
elseif pac_cfg.ctd.count_method == "Limit" then
|
-- 获取 SKU 在 grid_def.cell_type 的料格中的装载数量
|
nRet, loading_limit = wms_base.GetSKU_LoadingLimit( upgrad_item_list[n], pac_cfg.ctd.ctd_code, cell_type )
|
if nRet ~= 0 then
|
return 1, loading_limit
|
end
|
if qty >= loading_limit then
|
Q = math.floor(qty/loading_limit)
|
else
|
Q = 1
|
end
|
else
|
return 1, "料箱计数方法 = '"..pac_cfg.ctd.count_method.."'的算法还没实现!"
|
end
|
-- 从补料呼出的容器里找
|
nRet, Q = alloc_cell_in_out_cntr_list( strLuaDEID, pac_cfg, supplement_cntr_list, cell_type, upgrad_item_list[n], Q )
|
if ( nRet ~= 0 ) then return 1, Q end
|
if ( Q == 0 ) then break end
|
|
-- 从呼出容器里找
|
nRet, Q = alloc_cell_in_out_cntr_list( strLuaDEID, pac_cfg, out_cntr_result, cell_type, upgrad_item_list[n], Q )
|
if ( nRet ~= 0 ) then return 1, Q end
|
if ( Q == 0 ) then break end
|
|
-- 从新呼出一个料箱容器
|
out_cntr_list = {}
|
query_cntr_list = {}
|
nRet, Q, strRetInfo = generate_out_cntr_list( strLuaDEID, pac_cfg, cell_type, Q, out_cntr_list, query_cntr_list, out_cntr_result )
|
if (nRet ~= 0 ) then
|
return 2, "step5.1 发生错误! "..strRetInfo
|
end
|
if ( lua.IsTableEmpty( out_cntr_list ) == false ) then
|
-- 设置 out_cntr_list 中 empty_cell_list
|
nRet, strRetInfo = wms_pac.set_out_cntr_empty_cell( strLuaDEID, out_cntr_list )
|
if nRet ~= 0 then
|
return 2, strRetInfo
|
end
|
-- 把 upgrad_item_list 中的货品批分到 呼出的 out_cntr_list 中的容器中
|
nRet, strRetInfo = distribute_item_to_out_cntr_list( strLuaDEID, pac_cfg, upgrad_item_list[n], out_cntr_list )
|
if ( nRet ~= 0 ) then
|
return 2, "step5.2 发生错误! "..strRetInfo
|
end
|
wms_pac.reset_empty_cell_info( out_cntr_list )
|
lua.table_merge( out_cntr_result, out_cntr_list )
|
end
|
if ( Q == 0 ) then break end
|
end
|
end
|
end
|
|
-- MDF 20241220 ***
|
-- step6 检查升格后货品是否有没有匹配到料箱的,如果有需要降格
|
local xVolume
|
for n = 1, #upgrad_item_list do
|
if ( upgrad_item_list[n].ok == false ) then
|
-- 开始降格
|
cell_type_index = upgrad_item_list[n].upgrad_cell_index
|
while ( cell_type_index < 5 ) do
|
cell_type_index = cell_type_index + 1 -- 降一个料格
|
cell_type = pac_cfg.ctd.grid_box_def[cell_type_index].cell_type
|
|
if ( upgrad_item_list[n].S_CELL_TYPE < cell_type ) then break end
|
|
qty = upgrad_item_list[n].qty - upgrad_item_list[n].alloc_qty
|
|
if pac_cfg.ctd.count_method == "Mixed" or pac_cfg.ctd.count_method == "Volume" then
|
total_volume = qty*upgrad_item_list[n].volume
|
cell_volume = pac_cfg.ctd.grid_box_def[cell_type_index].volume
|
if ( total_volume > cell_volume ) then
|
--Q = math.floor( total_volume/cell_volume )
|
Q, pk_qty = calculate_box_count_by_volume( cell_volume, upgrad_item_list[n].volume, qty )
|
xVolume = upgrad_item_list[n].volume*(qty-pk_qty)
|
if ( xVolume > 0 ) then Q = Q + 1 end
|
else
|
Q = 1
|
end
|
elseif pac_cfg.ctd.count_method == "Limit" then
|
-- 获取 SKU 在 grid_def.cell_type 的料格中的装载数量
|
nRet, loading_limit = wms_base.GetSKU_LoadingLimit( upgrad_item_list[n], pac_cfg.ctd.ctd_code, cell_type )
|
if nRet ~= 0 then
|
return 1, loading_limit
|
end
|
if qty >= loading_limit then
|
Q = math.floor(qty/loading_limit)
|
xQty = qty - Q*loading_limit
|
if xQty > 0 then Q = Q + 1 end
|
else
|
Q = 1
|
end
|
else
|
return 1, "料箱计数方法 = '"..pac_cfg.ctd.count_method.."'的算法还没实现!"
|
end
|
-- 从补料呼出的容器里找
|
nRet, Q = alloc_cell_in_out_cntr_list( strLuaDEID, pac_cfg, supplement_cntr_list, cell_type, upgrad_item_list[n], Q )
|
if ( nRet ~= 0 ) then return 2, Q end
|
if ( Q == 0 ) then break end
|
-- 从呼出容器里找
|
nRet, Q = alloc_cell_in_out_cntr_list( strLuaDEID, pac_cfg, out_cntr_result, cell_type, upgrad_item_list[n], Q )
|
if ( nRet ~= 0 ) then return 2, Q end
|
if ( Q == 0 ) then break end
|
-- 从新呼出一个料箱容器
|
out_cntr_list = {}
|
nRet, Q, strRetInfo = generate_out_cntr_list( strLuaDEID, pac_cfg, cell_type, Q, out_cntr_list, query_cntr_list, out_cntr_result )
|
if (nRet ~= 0 ) then
|
return 2, "step6.1 发生错误! "..strRetInfo
|
end
|
if ( lua.IsTableEmpty( out_cntr_list ) == false ) then
|
-- 设置 out_cntr_list 中 empty_cell_list
|
nRet, strRetInfo = wms_pac.set_out_cntr_empty_cell( strLuaDEID, out_cntr_list )
|
if nRet ~= 0 then
|
return 2, strRetInfo
|
end
|
|
-- 把 upgrad_item_list 中的货品批分到 呼出的 out_cntr_list 中的容器中
|
nRet, strRetInfo = distribute_item_to_out_cntr_list( strLuaDEID, pac_cfg, upgrad_item_list[n], out_cntr_list )
|
if ( nRet ~= 0 ) then
|
return 2, "step6.2 发生错误! "..strRetInfo
|
end
|
wms_pac.reset_empty_cell_info( out_cntr_list )
|
lua.table_merge( out_cntr_result, out_cntr_list )
|
end
|
if ( Q == 0 ) then break end
|
end
|
end
|
end
|
|
-- step7 判断货品是否已经全部分配料箱完成,没完成报错
|
-- 把 item_list 和 upgrad_item_list 合并
|
lua.table_merge( item_list, upgrad_item_list )
|
|
-- 重置 supplement_cntr_list 和 out_cntr_list 中的empty_cell 等属性,
|
local s_cntr_have_empty_cell = wms_pac.reset_empty_cell_info( supplement_cntr_list )
|
local o_cntr_have_empty_cell = wms_pac.reset_empty_cell_info( out_cntr_result )
|
|
-- step8 遍历item_list 对没找到呼出料箱的货品进行单个呼出
|
-- 有可能因为重量超的原因上面分配的料格没办法装下货品
|
local Q1, Q2
|
for n = 1, #item_list do
|
if ( item_list[n].ok == false ) then
|
cell_type_index = string.byte( item_list[n].S_CELL_TYPE ) - string.byte( "A" ) + 1
|
while ( cell_type_index >= 1 ) do
|
cell_type = pac_cfg.ctd.grid_box_def[cell_type_index].cell_type
|
qty = item_list[n].qty - item_list[n].alloc_qty
|
|
-- 根据体积算的料格数量
|
if pac_cfg.ctd.count_method == "Mixed" or pac_cfg.ctd.count_method == "Volume" then
|
total_volume = qty*item_list[n].volume
|
cell_volume = pac_cfg.ctd.grid_box_def[cell_type_index].volume
|
if ( total_volume > cell_volume ) then
|
--Q = math.floor( total_volume/cell_volume )
|
Q1, pk_qty = calculate_box_count_by_volume( cell_volume, item_list[n].volume, qty )
|
xVolume = item_list[n].volume*(qty-pk_qty)
|
if ( xVolume > 0 ) then Q1 = Q1 + 1 end
|
else
|
Q1 = 1
|
end
|
-- 根据重量算的料格数量
|
Q2, pk_qty = calculate_box_count_by_weight( pac_cfg, cell_type_index, item_list[n].weight, qty )
|
xVolume = item_list[n].volume*(qty-pk_qty)
|
if ( xVolume > 0 ) then Q2 = Q2 + 1 end
|
|
if ( Q2 > Q1 ) then
|
Q = Q2
|
else
|
Q = Q1
|
end
|
elseif pac_cfg.ctd.count_method == "Limit" then
|
-- 获取 SKU 在 grid_def.cell_type 的料格中的装载数量
|
nRet, loading_limit = wms_base.GetSKU_LoadingLimit( item_list[n], pac_cfg.ctd.ctd_code, cell_type )
|
if nRet ~= 0 then
|
return 1, loading_limit
|
end
|
if qty >= loading_limit then
|
Q = math.floor(qty/loading_limit)
|
xQty = qty - Q*loading_limit
|
if xQty > 0 then Q = Q + 1 end
|
else
|
Q = 1
|
end
|
else
|
return 1, "料箱计数方法 = '"..pac_cfg.ctd.count_method.."'的算法还没实现!"
|
end
|
|
-- 从呼出容器里找
|
nRet, Q = alloc_cell_in_out_cntr_list( strLuaDEID, pac_cfg, out_cntr_result, cell_type, item_list[n], Q )
|
if ( nRet ~= 0 ) then return 2, Q end
|
if ( Q == 0 ) then break end
|
|
-- 从新呼出一个料箱容器
|
out_cntr_list = {}
|
nRet, Q, strRetInfo = generate_out_cntr_list( strLuaDEID, pac_cfg, cell_type, Q, out_cntr_list, query_cntr_list, out_cntr_result )
|
if (nRet ~= 0 ) then
|
return 2, "step8.1 发生错误! "..strRetInfo
|
end
|
if ( lua.IsTableEmpty( out_cntr_list ) == false ) then
|
-- 设置 out_cntr_list 中 empty_cell_list
|
nRet, strRetInfo = wms_pac.set_out_cntr_empty_cell( strLuaDEID, out_cntr_list )
|
if nRet ~= 0 then
|
return 2, strRetInfo
|
end
|
-- 把 upgrad_item_list 中的货品批分到 呼出的 out_cntr_list 中的容器中
|
nRet, strRetInfo = distribute_item_to_out_cntr_list( strLuaDEID, pac_cfg, item_list[n], out_cntr_list )
|
if ( nRet ~= 0 ) then
|
return 2, "step8.2 发生错误! "..strRetInfo
|
end
|
-- 清除呼出料箱列表中没有cell_list的节点
|
remove_no_cell_list_out_cntr_list( out_cntr_list )
|
if ( #out_cntr_list > 0 ) then
|
wms_pac.reset_empty_cell_info( out_cntr_list )
|
lua.table_merge( out_cntr_result, out_cntr_list )
|
end
|
end
|
|
if ( item_list[n].ok ) then break end
|
cell_type_index = cell_type_index - 1
|
end
|
end
|
end
|
return 0
|
end
|
|
--[[
|
item_list -- 需要预分配料箱的货品
|
pac_cfg -- 预分配料箱配置参数
|
{
|
wh_code, area_code 仓库,库区编码
|
factory
|
station 站台
|
aisle -- 可用巷道
|
bs_type 来源类型:入库单、入库波次
|
bs_no 来源单号
|
cntr_out_op_def = "料箱出库", --空料箱出库的作业定义
|
cntr_back_op_def = "货品入库" --料箱回库的主业定义
|
empty_cntr_out_rule = {} --空料箱呼出策略定义
|
ctd = {}
|
}
|
|
返回参数:
|
nRet 返回值:0 成功 1 -- 料箱不足 2 -- 程序错误
|
|
返回: pac_list 呼出的料箱列表 pac_detail_list 站台入库任务列表
|
]]
|
function wms_pac.Pre_Alloc_Cntr_CBG( strLuaDEID, pac_cfg, item_list )
|
local nRet, strRetInfo
|
local wh_code, area_code, station, bs_type, bs_no
|
local ctd_code
|
local sku_count = #item_list
|
local equipment = pac_cfg.equipment or ''
|
local supplement_cntr_list = {}
|
local out_cntr_result = {}
|
|
-- step1: 输入参数校验,及初始化
|
if ( sku_count == 0 ) then
|
return 0
|
end
|
|
if ( pac_cfg == nil or type( pac_cfg ) ~= "table" ) then
|
return 2, "Pre_Alloc_Cntr_CBG 函数输入参数错误: pac_cfg 必须有值,必须是 table 类型"
|
end
|
|
wh_code = lua.Get_StrAttrValue( pac_cfg.wh_code )
|
if ( wh_code == '' ) then
|
return 2, "Pre_Alloc_Cntr_CBG 函数输入参数错误: pac_cfg 参数中的 wh_code 必须有值!"
|
end
|
|
area_code = lua.Get_StrAttrValue( pac_cfg.area_code )
|
station = lua.Get_StrAttrValue( pac_cfg.station )
|
bs_type = lua.Get_StrAttrValue( pac_cfg.bs_type )
|
bs_no = lua.Get_StrAttrValue( pac_cfg.bs_no )
|
ctd_code = lua.Get_StrAttrValue( pac_cfg.ctd.ctd_code )
|
if ( ctd_code == "" ) then
|
return 2, "Pre_Alloc_Cntr_CBG 算法只适合 Cell_Box 类型的容器进行分配, pac_cfg中的参数 ctd_code 错误!"
|
end
|
local cntr_max_weight = pac_cfg.ctd.load_capacity
|
|
-- 如果 ctd 容器类型定义中定义过 混箱规则,这些规则一般会用到空料箱呼出规则中
|
-- 比如在国科项目中,不同产品线的物料是不能放在一个料箱的,而产品线也确定了料箱存放区域,空料箱要优先从这些区域呼出
|
|
local storage_area_set = {}
|
if not lua.IsTableEmpty( pac_cfg.empty_cntr_out_rule ) then
|
-- 根据 呼出空料箱策略,组织空料箱呼出库区
|
nRet, storage_area_set = wms_base.Get_Storage_Area_By_Strategy( pac_cfg.empty_cntr_out_rule, pac_cfg.mixing_attr_value )
|
if nRet ~= 0 then
|
return 1, storage_area_set
|
end
|
-- 对入库单中的库区和 空料箱呼出的库区 进行Check
|
for _, storage_area in ipairs( storage_area_set ) do
|
if storage_area.wh_code ~= pac_cfg.wh_code then
|
return 1, "空料箱呼出策略 '"..pac_cfg.empty_cntr_out_rule.no.."' 中定义的仓库编码和入库单中的仓库不一致!"
|
end
|
if lua.StrIsEmpty( storage_area.area_code ) then
|
return 1, "空料箱呼出策略 '"..pac_cfg.empty_cntr_out_rule.no.."' 中定义的策略必须指定到库区编码!"
|
end
|
end
|
end
|
|
-- step2 计算补料呼出料箱
|
local have_si_empty_cell = false
|
local pac_is_ok = false
|
|
if ( pac_cfg.ctd.si_enable ) then
|
nRet, supplement_cntr_list = wms_pac.get_replenishment_cntr_list( strLuaDEID, pac_cfg, item_list )
|
if ( nRet ~= 0 ) then
|
return 2, supplement_cntr_list
|
end
|
-- 首先判断一下补料呼出料箱中是否有存在 空料格, 有空料格设置 empty_cell_list 属性
|
have_si_empty_cell = wms_pac.set_replenishment_cntr_emptycell( strLuaDEID, supplement_cntr_list )
|
-- step1.3 检查补料箱中是否和合适料格做预分配
|
if not wms_pac.item_list_is_all_ok( item_list ) and have_si_empty_cell then
|
for _, sku in ipairs( item_list ) do
|
if ( sku.qty > sku.alloc_qty ) then
|
for _, si_cntr in ipairs( supplement_cntr_list ) do
|
nRet, strRetInfo = wms_pac.pre_alloc_sku_to_out_cntr( strLuaDEID, pac_cfg, sku, si_cntr )
|
if ( nRet ~= 0 ) then
|
return 1, strRetInfo
|
end
|
if sku.ok then
|
break
|
end
|
end
|
end
|
end
|
-- 删除 empty_cell_list 中已经分配出去的料格,返回 supplement_cntr_list 是否还有空料格
|
have_si_empty_cell = wms_pac.reset_empty_cell_info( supplement_cntr_list )
|
end
|
-- 判断是否已经完成预分配
|
pac_is_ok = wms_pac.item_list_is_all_ok( item_list )
|
end
|
|
if not pac_is_ok then
|
-- 继续呼出料箱
|
if lua.IsTableEmpty( storage_area_set ) then
|
nRet, strRetInfo = get_out_cntr_list_cbg( strLuaDEID, pac_cfg, item_list, supplement_cntr_list, out_cntr_result )
|
if ( nRet ~= 0 ) then
|
return 2, strRetInfo
|
end
|
else
|
-- 如果有呼出空料箱策略
|
for _, storage_area in ipairs( storage_area_set ) do
|
pac_cfg.area_code = storage_area.area_code
|
nRet, strRetInfo = get_out_cntr_list_cbg( strLuaDEID, pac_cfg, item_list, supplement_cntr_list, out_cntr_result )
|
if ( nRet ~= 0 ) then
|
return 2, strRetInfo
|
end
|
pac_is_ok = wms_pac.item_list_is_all_ok( item_list )
|
if pac_is_ok then
|
break
|
end
|
end
|
end
|
end
|
|
local msg_list = {} -- 保存无法分配料格的货品数量
|
for n = 1, #item_list do
|
if ( item_list[n].ok == false ) then
|
local qty = item_list[n].qty-item_list[n].alloc_qty
|
local msg = "系统没有匹配到货品编码 = '"..item_list[n].S_ITEM_CODE.."'的适配料箱进行预分配, 货品的适配料格类型 = '"..item_list[n].S_CELL_TYPE.."', 数量 = "..qty
|
table.insert( msg_list, msg )
|
end
|
end
|
if ( #msg_list > 0 ) then
|
-- 这些货品没有合适的料箱
|
return 1, lua.table2str( msg_list )
|
end
|
return 0, supplement_cntr_list, out_cntr_result
|
end
|
|
-- 生成 【Pre_Alloc_Container】【Pre_Alloc_CNTR_Detail】
|
-- replenish = Y 表示是补料呼出料箱 station -- 站台
|
local function generate_pac_detail( strLuaDEID, pac_cfg, cntr_code, replenish, cell_list, pac_list, pac_detail_list )
|
local nRet, strRetInfo
|
local n
|
|
local pac = m3.AllocObject2( strLuaDEID, "Pre_Alloc_Container" )
|
pac.S_CNTR_CODE = cntr_code
|
pac.C_REPLENISH = replenish
|
pac.S_BS_TYPE = pac_cfg.bs_type
|
pac.S_BS_NO = pac_cfg.bs_no
|
pac.S_STATION_NO = pac_cfg.station
|
pac.S_OUT_OP_NAME = pac_cfg.cntr_out_op_def
|
pac.S_BACK_OP_NAME = pac_cfg.cntr_back_op_def
|
pac.S_FACTORY = pac_cfg.factory
|
|
nRet, pac = m3.CreateDataObj2(strLuaDEID, pac)
|
if (nRet ~= 0 ) then return 1, "创建【预分配容器】失败!"..pac end
|
table.insert( pac_list, pac )
|
|
local pac_detail
|
|
for n = 1, #cell_list do
|
pac_detail = m3.AllocObject2( strLuaDEID, "Pre_Alloc_CNTR_Detail" )
|
pac_detail.S_PAC_NO = pac.S_PAC_NO
|
pac_detail.S_CNTR_CODE = cntr_code
|
pac_detail.S_CELL_NO = cell_list[n].cell_no
|
pac_detail.S_STATION_NO = pac_cfg.station
|
|
pac_detail.S_STORER = cell_list[n].sku.S_STORER
|
pac_detail.S_ITEM_CODE = cell_list[n].item_code
|
pac_detail.S_ITEM_STATE = cell_list[n].sku.S_ITEM_STATE
|
pac_detail.S_ITEM_NAME = cell_list[n].item_name
|
|
pac_detail.S_OWNER = cell_list[n].sku.S_OWNER
|
pac_detail.S_SUPPLIER_NO = cell_list[n].sku.S_SUPPLIER_NO
|
pac_detail.S_BATCH_NO = cell_list[n].sku.S_BATCH_NO
|
pac_detail.S_SERIAL_NO = cell_list[n].sku.S_SERIAL_NO
|
pac_detail.D_PRD_DATE = cell_list[n].sku.D_PRD_DATE
|
pac_detail.D_EXP_DATE = cell_list[n].sku.D_EXP_DATE
|
|
pac_detail.F_WEIGHT = cell_list[n].weight
|
pac_detail.F_VOLUME = cell_list[n].volume
|
|
pac_detail.S_WMS_BN = cell_list[n].wms_bn
|
pac_detail.F_QTY = cell_list[n].qty
|
|
pac_detail.S_BS_TYPE = pac_cfg.bs_type
|
pac_detail.S_BS_NO = pac_cfg.bs_no
|
pac_detail.N_BS_ROW_NO = cell_list[n].row
|
|
-- 把SKU中的明细扩展属性带入
|
for _, udf_attr in ipairs(UDF_ATTRS) do
|
pac_detail[udf_attr] = cell_list[n].sku[udf_attr]
|
end
|
|
nRet, pac_detail = m3.CreateDataObj2(strLuaDEID, pac_detail)
|
if (nRet ~= 0 ) then return 1, "创建【预分配容器明细】失败!"..pac_detail end
|
|
table.insert( pac_detail_list, pac_detail )
|
end
|
return 0
|
end
|
|
-- 从数据对象(字段)中获取 attrs_array 中的属性值
|
local function get_data_object_attr_value( object_data, attrs_array )
|
local attr_value = {}
|
local key_value = ''
|
local value
|
|
for _, attr in ipairs( attrs_array ) do
|
value = object_data[attr] or ''
|
key_value = key_value..attr.."='"..value.."';"
|
attr_value[attr] = value
|
end
|
return lua.trim_laster_char( key_value ), attr_value
|
end
|
|
--[[
|
把 item_list 根据容器类型定义 ctd 中的混箱规则,把相同混箱规则的 item 分组,生成 split_item_list
|
ctd.mixing_attrs_def = {
|
{attr = "S_BATCH_NO", type = "string"},
|
..
|
}
|
ctd.mixing_attrs = {"S_BATCH_NO",...}
|
|
split_item_list = {
|
mixing_attr_value = {S_BATCH_NO="xxx",S_X="xxx"},
|
mixing_key = "S_BATCH_NO='xx';S_STATE='xx'"
|
item_list = {
|
{S_ITEM_CODE = "X1",...},
|
}
|
}
|
--]]
|
local function split_item_list_by_mixing_rule( ctd, item_list, split_item_list )
|
local mixing_attr_value = {}
|
local find, mixing_key
|
|
if lua.isTableEmpty( ctd.mixing_attrs ) then
|
return 1, "容器类型定义'"..ctd.ctd_code.."'中的混箱规则不能为空!"
|
end
|
for _, item in ipairs( item_list ) do
|
mixing_key, mixing_attr_value = get_data_object_attr_value( item, ctd.mixing_attrs )
|
find = false
|
for _, split_item in ipairs( split_item_list ) do
|
if split_item.mixing_key == mixing_key then
|
find = true
|
table.insert( split_item.item_list, item )
|
break
|
end
|
end
|
if not find then
|
local split_item = {
|
mixing_attr_value = mixing_attr_value,
|
mixing_key = mixing_key,
|
item_list = {}
|
}
|
table.insert( split_item.item_list, item )
|
table.insert( split_item_list, split_item )
|
end
|
end
|
return 0
|
end
|
|
--[[
|
预分配料箱,物料预先指定存储料格及料格中最大存储数量,或重量
|
如果货品
|
Designated Material Grid -- 简称 DMG 意思是每个货品都指定了一种料格进行存储
|
特点:
|
一种货品保存在一种类型的料格
|
料格中货品最大存储数量计算方法有两种, 1 -- 系统设置最大储藏数量 2 -- 系统设置重量后根据料格载重进行计算
|
在匹配料箱时,一个料箱只能用相同的数量计算方法
|
|
来源项目: 艾默生料箱库
|
|
输入参数:
|
pac_cfg -- 预分配料箱配置参数
|
{
|
handling_model -- 搬运模式 AGV;PickingAGV;AS/RS
|
factory 工厂标识
|
wh_code, area_code 仓库,库区编码
|
station 站台
|
bs_type 来源类型:入库单、入库波次
|
bs_no 来源单号
|
aisle 可用巷道 {"A01","A02",...}
|
cntr_out_op_def = "料箱出库", --空料箱出库的作业定义
|
cntr_back_op_def = "货品入库" --料箱回库的主业定义
|
empty_cntr_out_rule = "xxx" --空料箱呼出策略
|
}
|
|
---- 下面两个参数是系统运算后的结果返回 ----
|
pac_list -- Pre_Alloc_Container 对象列表
|
pac_detail_list Pre_Alloc_CNTR_Detail 列表
|
--]]
|
function wms_pac.Pre_Alloc_Cntr( strLuaDEID, pac_cfg, pac_list, pac_detail_list )
|
local nRet, strRetInfo, n
|
|
lua.DebugEx( strLuaDEID, "In Pre_Alloc_Cntr", "OK")
|
lua.DebugEx( strLuaDEID, "pac_cfg --> ", pac_cfg )
|
|
-- step1: 输入参数合法性检查
|
local ctd_list
|
nRet, ctd_list = wms_pac.Get_ItemList_GroupBy_CntrType( strLuaDEID, pac_cfg )
|
if ( nRet ~= 0 ) then
|
return 1, ctd_list
|
end
|
|
-- 如果有输入‘空料箱呼出策略’ 需要从系统获取该策略
|
if not lua.StrIsEmpty( pac_cfg.empty_cntr_out_rule ) then
|
local strategy = {}
|
nRet, strategy = wms_base.GetStrategyInfo( "EmptyCntrOut_Strategy", pac_cfg.empty_cntr_out_rule )
|
if nRet ~= 0 then
|
return 1, "在获取'空料箱呼出策略'时失败! "..strategy
|
end
|
pac_cfg.empty_cntr_out_rule = strategy
|
end
|
|
local area_code = pac_cfg.area_code or ''
|
local station = pac_cfg.station or ''
|
|
|
-- 根据容器类型进行料箱预分配
|
local si_match_attrs, str_val
|
local count_method
|
|
local supplement_cntr_list = {}
|
local out_cntr_list = {}
|
|
for n = 1, #ctd_list do
|
-- 通过容器类型定义设置 料箱呼出规则
|
nRet, pac_cfg.ctd = wms_cntr.GetCTDInfo( ctd_list[n].ctd_code )
|
if ( nRet ~= 0 ) then
|
return 1, "容器类型定义'"..ctd_list[n].ctd_code.."'转换数据格式! --> "..pac_cfg.ctd
|
end
|
|
-- 入库货品初始化
|
for _, item in ipairs( ctd_list[n].item_list ) do
|
if ( lua.StrIsEmpty( item.S_CELL_TYPE ) ) then
|
return 1, "编码'"..item.S_ITEM_CODE.."'的 SKU 没有定义料格类型/S_CELL_TYPE"
|
end
|
count_method = lua.Get_StrAttrValue( item.S_COUNT_METHOD )
|
if ( count_method ~= "Volume" and count_method ~= "Weight" and count_method ~= "Limit" ) then
|
return 1, "编码'"..item.S_ITEM_CODE.."'的 SKU 定义的料格计算货品容量的方法不符合 DMG 算法的要求!"
|
end
|
if ( count_method == "Volume" ) then
|
if ( item.volume <= 0 ) then
|
return 1, "编码'"..item.S_ITEM_CODE.."'的 SKU 定义的料格计数方法是根据体积计算,没有设置SKU的体积!"
|
end
|
elseif ( count_method == "Weight" ) then
|
if ( item.weight <= 0 ) then
|
return 1, "编码'"..item.S_ITEM_CODE.."'的 SKU 定义的料格计数方法是根据重量计算,没有设置SKU的重量!"
|
end
|
end
|
item.mixing_rule = {}
|
if ( pac_cfg.ctd.have_mixing_rule ) then
|
-- 获取 SKU 的混箱属性
|
for _, attr in ipairs( pac_cfg.ctd.mixing_attrs ) do
|
item.mixing_rule[attr] = lua.Get_StrAttrValue( item[attr])
|
end
|
end
|
end
|
|
-- 对pac_cfg中的入库作业定义进行处理,获取入库作业的上架策略,通过这个策略去查找空料箱
|
if ( pac_cfg.ctd.ecda_rule == "Flex match" ) then
|
-- 灵活匹配可以匹配多种类型料格
|
|
-- 需要进一步对入库货品进行分类(根据混箱规则,比如相同产品线)
|
if pac_cfg.ctd.have_mixing_rule then
|
-- 根据混箱规则对入库货品明细进行分割,相同混箱规则的放一起,加入 split_item_list
|
-- split_item_list = {{"mixing_value":{S_UDF01="PRD-01"}, item_list:{}},...}
|
local split_item_list = {}
|
nRet, strRetInfo = split_item_list_by_mixing_rule( pac_cfg.ctd, ctd_list[n].item_list, split_item_list )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
-- 分别对有相同混箱规则的货品进行 容器预分配
|
for _, split_item in ipairs( split_item_list ) do
|
local s_cntr_list = {}
|
local o_cntr_list = {}
|
pac_cfg.mixing_attr_value = split_item.mixing_attr_value
|
nRet, s_cntr_list, o_cntr_list = wms_pac.Pre_Alloc_Cntr_CBG( strLuaDEID, pac_cfg, split_item.item_list )
|
if ( nRet ~= 0 ) then
|
return nRet, s_cntr_list
|
end
|
lua.table_merge( supplement_cntr_list, s_cntr_list )
|
lua.table_merge( out_cntr_list, o_cntr_list )
|
end
|
|
else
|
nRet, supplement_cntr_list, out_cntr_list = wms_pac.Pre_Alloc_Cntr_CBG( strLuaDEID, pac_cfg, ctd_list[n].item_list )
|
if ( nRet ~= 0 ) then
|
return nRet, supplement_cntr_list
|
end
|
end
|
elseif ( pac_cfg.ctd.ecda_rule == "SDM Grid" ) then
|
-- 用于标识特定区域必须使用单一指定材料
|
nRet, supplement_cntr_list, out_cntr_list = wms_pac.Pre_Alloc_Cntr_DMG( strLuaDEID, pac_cfg, ctd_list[n].item_list )
|
if ( nRet ~= 0 ) then
|
return nRet, supplement_cntr_list
|
end
|
else
|
return 1, "系统不支持名为'"..pac_cfg.ctd.ecda_rule.."'的料箱呼出规则!"
|
end
|
|
-- step9 创建 预分配容器
|
-- 20241108 HAN 补料呼出的料箱和空料箱呼出的如果料箱号是一样的需要合并一下,合并在补料箱列表
|
-- 如果呼出的有补料和空料箱的时候要检查
|
for n = 1, #supplement_cntr_list do
|
for m = 1, #out_cntr_list do
|
if (supplement_cntr_list[n].cntr_code == out_cntr_list[m].cntr_code) then
|
for i = 1, #out_cntr_list[m].cell_list do
|
table.insert( supplement_cntr_list[n].cell_list, out_cntr_list[m].cell_list[i])
|
remove_empty_cell( supplement_cntr_list[n], out_cntr_list[m].cell_list[i].cell_no )
|
end
|
out_cntr_list[m].cell_list = {}
|
end
|
end
|
end
|
|
-- 生成 【Pre_Alloc_Container】【Pre_Alloc_CNTR_Detail】
|
local cell_list
|
for n = 1, #supplement_cntr_list do
|
cell_list = supplement_cntr_list[n].cell_list
|
if ( #cell_list > 0 ) then
|
nRet, strRetInfo = generate_pac_detail( strLuaDEID, pac_cfg, supplement_cntr_list[n].cntr_code, 'Y',
|
cell_list, pac_list, pac_detail_list )
|
if ( nRet ~= 0 ) then
|
return 2, "补料 generate_pac_detail 发生错误! "..strRetInfo
|
end
|
end
|
end
|
|
for n = 1, #out_cntr_list do
|
cell_list = out_cntr_list[n].cell_list
|
if ( #cell_list > 0 ) then
|
nRet, strRetInfo = generate_pac_detail( strLuaDEID, pac_cfg, out_cntr_list[n].cntr_code, 'N',
|
cell_list, pac_list, pac_detail_list )
|
if ( nRet ~= 0 ) then
|
return 2, "呼出空料箱 generate_pac_detail 发生错误! "..strRetInfo
|
end
|
end
|
end
|
end
|
|
-- 设置入库单业务状态为 PreAlloc_OK/预分配完成(ps:入库需要的料箱已经确定)
|
local strUpdateSql
|
local strCondition
|
if ( pac_cfg.bs_type == "Inbound_Order" ) then
|
strUpdateSql = "N_B_STATE = "..INBOUND_STATE.PreAlloc_OK
|
strCondition = "S_NO = '"..pac_cfg.bs_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Inbound_Order", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then
|
return 2, "更新【入库单】信息失败!"..strRetInfo
|
end
|
elseif ( pac_cfg.bs_type == "Inbound_Wave" ) then
|
strUpdateSql = "N_B_STATE = "..IN_WAVE_STATE.PreAlloc_OK
|
strCondition = "S_WAVE_NO = '"..pac_cfg.bs_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Inbound_Wave", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then
|
return 2, "更新【入库波次】信息失败!"..strRetInfo
|
end
|
end
|
return 0
|
end
|
|
--[[
|
预分配容器 回库 后表示一个入库的任务完成,需要判断一下入库单是否可以完成
|
--]]
|
|
function wms_pac.After_PAC_Finish( strLuaDEID, pac_no )
|
local nRet, strRetInfo
|
|
if ( pac_no == nil or pac_no == '' ) then
|
return 1, "wms_pac.After_PAC_Finish 函数中 pac_no 必须有值!"
|
end
|
|
-- 获取 Pre_Alloc_CNTR_Detail
|
local strOrder = ''
|
local strCondition = "S_PAC_NO = '"..pac_no.."'"
|
|
nRet, strRetInfo = mobox.queryDataObjAttr( strLuaDEID, "Pre_Alloc_CNTR_Detail", strCondition, strOrder )
|
if ( nRet ~= 0 ) then return 1, "获取【预分配容器明细】失败! "..strRetInfo end
|
if ( strRetInfo == '' ) then
|
return 0
|
end
|
|
local retObjs = json.decode( strRetInfo )
|
local n
|
local pac_detail = {}
|
|
for n = 1, #retObjs do
|
nRet, pac_detail = m3.ObjAttrStrToLuaObj( "Pre_Alloc_CNTR_Detail", lua.table2str(retObjs[n].attrs) )
|
if ( nRet ~= 0 ) then return 1, "m3.ObjAttrStrToLuaObj(Pre_Alloc_CNTR_Detail) 失败! "..pac_detail end
|
-- 根据业务来源加 F_ACC_I_QTY/累计入库数量
|
if ( pac_detail.bs_type == "Inbound_Order" ) then
|
if ( pac_detail.bs_no ~= nil and pac_detail.bs_no ~= '' ) then
|
strCondition = "S_IO_NO = '"..pac_detail.bs_no.."' AND S_ITEM_CODE = '"..pac_detail.item_code.."'"
|
local strSetAttr = "F_ACC_I_QTY = F_ACC_I_QTY +"..pac_detail.act_qty
|
if ( lua.equation( 0, pac_detail.cancel_qty ) == false ) then
|
strSetAttr = strSetAttr..", F_ACC_C_QTY = F_ACC_C_QTY + "..pac_detail.cancel_qty
|
end
|
nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "Inbound_Detail", strCondition, strSetAttr )
|
if (nRet ~= 0) then return 1, "设置【Inbound_Detail】累计入库数量失败!"..strRetInfo end
|
end
|
end
|
if ( pac_detail.bs_type == 'Inbound_Wave' ) then
|
if ( pac_detail.bs_no ~= nil and pac_detail.bs_no ~= '' ) then
|
strCondition = "S_WAVE_NO = '"..pac_detail.bs_no.."' AND S_ITEM_CODE = '"..pac_detail.item_code.."'"
|
local strSetAttr = "F_ACC_I_QTY = F_ACC_I_QTY +"..pac_detail.act_qty
|
if ( lua.equation( 0, pac_detail.cancel_qty ) == false ) then
|
strSetAttr = strSetAttr..", F_ACC_C_QTY = F_ACC_C_QTY + "..pac_detail.cancel_qty
|
end
|
nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "IW_Detail", strCondition, strSetAttr )
|
if (nRet ~= 0) then return 1, "设置【IW_Detail】累计入库数量失败!"..strRetInfo end
|
end
|
end
|
end
|
return 0
|
end
|
|
return wms_pac
|