--[[
|
版本: Version 1.0
|
创建日期: 2025-4-20
|
创建人: HAN
|
|
WMS-Basis-Model-Version: V15.5
|
|
功能:
|
在处理入库作业时,将入库单明细中的货品预先分配到具体容器料格的过程在WMS系统里叫 预分配容器
|
一般用在料箱库,空料箱有多种规格,根据货品中的设置呼出适配的料格
|
|
主要函数:
|
-- wms_pac.Pre_Alloc_Cntr_DMG
|
|
supplement_cntr_list 和 out_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_state, storer, item_name}] -- 呼出的补料料箱中的空料格 cell 属性同下面的 cell_list
|
cell_list:{
|
{ cntr_code:"", cell_no:"", item_code:"xx", item_name:"", wms_bn:"SN01", weight, volume, qty:10 ,sum_volume:10, sum_weigt:10}
|
}
|
}
|
|
--]]
|
wms_cntr = require ("wms_container")
|
wms_wh = require ("wms_wh")
|
|
local wms_pac = {_version = "0.1.1"}
|
|
local BOX_MAX_WEIGHT = 0
|
local CHECK_CAPACITY = flase -- 是否检查超重
|
|
-- 需要查询的物料货品属性,一般用在 明细表 中如入库单明细,出库单明细
|
local DETAIL_ATTRS = {
|
"S_STORER", "S_ITEM_CODE", "S_ITEM_NAME", "S_ITEM_STATE", "S_ITEM_SPEC","S_BATCH_NO","S_SERIAL_NO", "S_WMS_BN",
|
"D_PRD_DATE", "D_EXP_DATE", "S_OWNER", "S_SUPPLIER_NO", "N_ROW_NO","F_QTY",
|
"S_UDF01", "S_UDF02", "S_UDF03", "S_UDF04", "S_UDF05", "S_UDF06", "S_UDF07", "S_UDF08", "S_UDF09", "S_UDF10",
|
"S_UDF11", "S_UDF12", "S_UDF13", "S_UDF14", "S_UDF15", "S_UDF16", "S_UDF17", "S_UDF18", "S_UDF19", "S_UDF20"
|
}
|
local SKU_ATTRS = {
|
"F_WEIGHT","F_VOLUME","S_CTD_CODE", "S_CELL_TYPE", "S_AVL_SPEC", "S_ABCTYPE", "N_LOADING_LIMIT", "F_LOAD_CAPACITY","S_COUNT_METHOD","S_SKU_GRID_PARM"
|
}
|
|
-- 设置 out_cntr_list 中的 cell_empty
|
-- out_cntr_list = {{ cntr_code,cntr_good_weight,cell_type,empty_cell_list = {},,full = false,cell_list = {},...}
|
function wms_pac.set_out_cntr_empty_cell( strLuaDEID, out_cntr_list )
|
local nRet, strRetInfo, strCondition, strOrder, n, m, empty_cell_count
|
local cntr_cell_objs, cell_attr
|
|
for n = 1, #out_cntr_list do
|
strCondition = "S_CNTR_CODE = '"..out_cntr_list[n].cntr_code.."' AND N_EMPTY_FULL = 0"
|
strOrder = "S_CELL_NO"
|
nRet, cntr_cell_objs = m3.QueryDataObject(strLuaDEID, "Container_Cell", strCondition, strOrder )
|
if (nRet ~= 0) then return 1, cntr_cell_objs end
|
|
if ( cntr_cell_objs ~= '') then
|
for m = 1, #cntr_cell_objs do
|
cell_attr = m3.KeyValueAttrsToObjAttr(cntr_cell_objs[m].attrs)
|
local empty_cell = {
|
cntr_code = out_cntr_list[n].cntr_code,
|
cell_no = cell_attr.S_CELL_NO,
|
item_code = "",
|
item_name = "",
|
entry_batch_no = "",
|
qty = 0, sum_volume = 0, sum_weigt = 0
|
}
|
table.insert( out_cntr_list[n].empty_cell_list, empty_cell )
|
end
|
end
|
end
|
return 0
|
end
|
--[[
|
获取入库单,入库波次中需要入库的物料信息,并且根据容器类型进行区分
|
输入参数:
|
paramter -- 预分配料箱配置参数
|
{
|
wh_code, area_code 仓库,库区编码
|
station 站台
|
bs_type 来源类型:入库单、入库波次
|
bs_no 来源单号
|
}
|
返回:ctd_list = {
|
{ctd_code="CTD-003",item_list={..}},
|
...
|
}
|
--]]
|
function wms_pac.Get_ItemList_GroupBy_CntrType( strLuaDEID, paramter )
|
local nRet, strRetInfo, n, isOk
|
-- step1: 输入参数合法性检查
|
isOk, strRetInfo = wms_base.PreAllocCntr_CFG_Check( paramter )
|
if not isOk then
|
return 1, strRetInfo
|
end
|
|
-- step2: 获取入库货品明细 item_lis, 这个货品列表要根据容器类型进行区分,因此保存在 ctd_list
|
-- { {ctd_code="", item_lits = {} },... }
|
-- 确定要联表查询的表和条件
|
local strTable, strCondition
|
if ( paramter.bs_type == "Inbound_Order" ) then
|
strTable = "TN_Inbound_Detail a LEFT JOIN TN_SKU b ON a.S_ITEM_CODE = b.S_ITEM_CODE"
|
strCondition = "a.S_IO_NO = '"..paramter.bs_no.."'"
|
else
|
strTable = "TN_IW_Detail a LEFT JOIN TN_SKU b ON a.S_ITEM_CODE = b.S_ITEM_CODE"
|
strCondition = "a.S_WAVE_NO = '"..paramter.bs_no.."'"
|
end
|
|
-- 要查询的属性
|
local detail_attrs_count = #DETAIL_ATTRS
|
local sku_attrs_count = #SKU_ATTRS
|
local strAttrs = ""
|
|
for n = 1, detail_attrs_count do
|
strAttrs = strAttrs.."a."..DETAIL_ATTRS[n]..","
|
end
|
for n = 1, sku_attrs_count do
|
strAttrs = strAttrs.."b."..SKU_ATTRS[n]..","
|
end
|
strAttrs = lua.trim_laster_char( strAttrs )
|
|
|
local strOrder = "a.N_ROW_NO"
|
-- 注意最多只能 2000 条明细, 如果有超过 2000 的记录概要分页查询函数,一般的入库单不会有这么多记录
|
nRet, strRetInfo = mobox.queryMultiTable(strLuaDEID, strAttrs, strTable, 2000, strCondition, strOrder )
|
if (nRet ~= 0) then
|
return 2,"QueryDataObject失败!"..strRetInfo
|
end
|
if ( strRetInfo == '' ) then
|
return 1, paramter.bs_type.."'"..paramter.bs_no.."'明细为空!"
|
end
|
|
local ret_attr = json.decode(strRetInfo)
|
local m
|
local ctd_list = {}
|
local find, success
|
|
for n = 1, #ret_attr do
|
local item = {}
|
for m = 1, detail_attrs_count do
|
item[DETAIL_ATTRS[m]] = ret_attr[n][m]
|
end
|
for m = 1, sku_attrs_count do
|
item[SKU_ATTRS[m]] = ret_attr[n][m+detail_attrs_count]
|
end
|
item.qty = lua.Get_NumAttrValue( item.F_QTY )
|
item.volume = lua.Get_NumAttrValue( item.F_VOLUME )
|
item.weight = lua.Get_NumAttrValue( item.F_WEIGHT )
|
item.row = lua.Get_NumAttrValue( item.N_ROW_NO )
|
item.alloc_qty = 0
|
item.ok = false
|
item.cntr_cell_list = {} -- 预分配的料格列表
|
item.sku_grid_parm = ''
|
if not lua.StrIsEmpty( item.S_SKU_GRID_PARM ) then
|
success, item.sku_grid_parm = pcall( json.decode, item.S_SKU_GRID_PARM )
|
if ( success == false ) then
|
return 1, "SKU 编码 = '"..sku.S_ITEM_CODE.."' 的数据对象中 S_SKU_GRID_PARM 不符合json规范!"
|
end
|
end
|
|
-- 获取SKU的容器定义类型 S_CTD_CODE
|
ctd_code = item.S_CTD_CODE or ''
|
if ( ctd_code == '' ) then
|
return 1, "编码 = '"..item.S_ITEM_CODE.."' 的SKU没有定义容器类型!"
|
end
|
find = false
|
if ( ctd_list ~= nil ) then
|
for i = 1, #ctd_list do
|
if ( ctd_list[i].ctd_code == ctd_code ) then
|
table.insert( ctd_list[i].item_list, item )
|
find = true
|
break
|
end
|
end
|
end
|
|
if not find then
|
local ctd_item = {
|
ctd_code = ctd_code,
|
item_list = {item}
|
}
|
table.insert( ctd_list, ctd_item )
|
end
|
end
|
return 0, ctd_list
|
end
|
|
-- 检测需要入库预分配的货品清单是否已经全部有了预分配
|
function wms_pac.item_list_is_all_ok( item_list )
|
for _, item in ipairs( item_list ) do
|
if not item.ok then
|
return false
|
end
|
end
|
return true
|
end
|
|
-- 把匹配到的料格 cell_item 加入 呼出料箱容器清单 out_cntr_list
|
-- cntr_mixing_rule 为补料容器的混箱规则
|
function wms_pac.put_cell_item_to_out_cntr_list( out_cntr_list, cntr_good_weight, cell_item, cntr_mixing_rule )
|
local n
|
local bFind = false
|
|
if cntr_mixing_rule == nil then cntr_mixing_rule = {} end
|
|
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
|
|
if (bFind == false) then
|
local out_cntr = {}
|
out_cntr = {
|
cntr_code = cell_item.cntr_code,
|
cell_type = cell_item.cell_type,
|
full = false,
|
cntr_mixing_rule = cntr_mixing_rule, -- 和混箱策略相关的属性值
|
empty_cell_list = {},
|
cntr_good_weight = cntr_good_weight + cell_item.sum_weight,
|
cell_list = {}
|
}
|
table.insert( out_cntr.cell_list, cell_item )
|
table.insert( out_cntr_list, out_cntr )
|
end
|
end
|
|
-- 遍历补料呼出料箱,判断补料呼出料箱中是否有存在 空料格, 设置item中的 empty_cell 属性
|
-- 返回是否可以用补料箱进行预分配
|
function wms_pac.set_replenishment_cntr_emptycell( strLuaDEID, supplement_cntr_list )
|
local n, nRet, strRetInfo, strCondition, strOrder, m
|
local data_objects
|
local cell
|
local have_empty_cell = false
|
|
strOrder = "S_CELL_NO"
|
for n = 1, #supplement_cntr_list do
|
-- 空料格
|
strCondition = "S_CNTR_CODE = '"..supplement_cntr_list[n].cntr_code.."' AND N_EMPTY_FULL = 0"
|
nRet, data_objects = m3.QueryDataObject(strLuaDEID, "Container_Cell", strCondition, strOrder )
|
if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objects end
|
if ( data_objects ~= '') then
|
for m = 1, #data_objects do
|
cell = m3.KeyValueAttrsToObjAttr(data_objects[m].attrs)
|
local empty_cell = {
|
cntr_code = supplement_cntr_list[n].cntr_code,
|
cell_no = cell.S_CELL_NO,
|
item_code = "", item_state = "", storer = "", item_name = "", wms_bn = "",
|
qty = 0, sum_volume = 0, sum_weigt = 0
|
}
|
table.insert( supplement_cntr_list[n].empty_cell_list, empty_cell )
|
have_empty_cell = true
|
end
|
else
|
-- 没有空料箱格
|
supplement_cntr_list[n].full = true
|
end
|
end
|
return have_empty_cell
|
end
|
|
-- 检查 sku 是否符合混箱规则
|
function wms_pac.sku_complies_with_mixing_rule ( ctd, sku, cntr_mixing_rule )
|
local sku_value, cntr_mixing_rule_value
|
|
if lua.isTableEmpty( cntr_mixing_rule ) then
|
return 1, "wms_pac.sku_complies_with_mixing_rule 函数中 cntr_mixing_rule 不合规!"
|
end
|
for _, attr in ipairs( ctd.mixing_attrs ) do
|
sku_value = sku[attr]
|
if sku_value == nil then
|
return 1, "在判断是否符合混箱规则时,发现 SKU 缺少属性'"..attr.."'"
|
end
|
cntr_mixing_rule_value = cntr_mixing_rule[attr]
|
if cntr_mixing_rule_value == nil then
|
return 1, "在判断是否符合混箱规则时,发现 容器扩展属性中 缺少属性'"..attr.."'"
|
end
|
if sku_value ~= cntr_mixing_rule_value then
|
return 0, false
|
end
|
end
|
return 0, true
|
end
|
|
-- 把呼出容器列表中的 empty_cell 清理一下,如果 item_code 有值表示已经分配了货品
|
function wms_pac.reset_empty_cell_info( cntr_list )
|
local empty_cell_list
|
local n, m
|
local have_empty_cell = false -- 说明cntr_list是否有空料箱
|
|
for n = 1, #cntr_list do
|
empty_cell_list = {}
|
for m = 1, #cntr_list[n].empty_cell_list do
|
if (cntr_list[n].empty_cell_list[m].item_code == '') then
|
local empty_cell = {
|
cntr_code = cntr_list[n].empty_cell_list[m].cntr_code,
|
cell_no = cntr_list[n].empty_cell_list[m].cell_no,
|
item_code = "",
|
item_name = "",
|
wms_bn = "",
|
weight = 0, volume = 0,
|
qty = 0, sum_volume = 0, sum_weigt = 0
|
}
|
table.insert( empty_cell_list, empty_cell )
|
end
|
end
|
cntr_list[n].empty_cell_list = empty_cell_list
|
if ( 0 == #empty_cell_list ) then
|
cntr_list[n].full = true
|
else
|
have_empty_cell = true
|
end
|
end
|
return have_empty_cell
|
end
|
|
--[[
|
计算在容器 out_cntr 里预分配 sku 的数量,注意这个时候的 out_cntr 已经是在呼出容器的队列,比如已经在补料呼出队列,呼出空料箱队列
|
ctd -- 容器类型定义
|
sku -- 入库商品
|
out_cntr = {
|
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_state, storer, item_name}} -- 空料格
|
cell_list:{
|
{ cntr_code:"", cell_no:"", item_code:"xx", item_name:"", wms_bn:"SN01", weight, volume, qty:10 ,sum_volume:10, sum_weigt:10}
|
}
|
}
|
bs_no -- 入库波次号/入库单号
|
--]]
|
function wms_pac.pre_alloc_sku_to_out_cntr( strLuaDEID, pac_cfg, sku, out_cntr )
|
local nRet, Q, strRetInfo
|
local match_ok = false
|
local sku_count_method = lua.Get_StrAttrValue( sku.S_COUNT_METHOD )
|
local qty -- 需要分配料箱格的货品数量
|
|
if ( sku_count_method == '' ) then
|
return 1, "SKU '"..sku.S_ITEM_CODE.."' 没有定义计数方法 S_COUNT_METHOD"
|
end
|
--补料料箱不满,且料格规格和SKU设定的料格规格相等
|
if not out_cntr.full and out_cntr.cell_type == sku.S_CELL_TYPE then
|
if ( pac_cfg.ctd.have_mixing_rule ) then
|
nRet, match_ok = wms_pac.sku_complies_with_mixing_rule ( pac_cfg.ctd, sku, out_cntr.cntr_mixing_rule )
|
if ( nRet ~= 0 ) then
|
return 1, "wms_pac.sku_complies_with_mixing_rule 时出错! "..match_ok
|
end
|
else
|
match_ok = true
|
end
|
end
|
Q = 0
|
if match_ok then
|
qty = sku.qty - sku.alloc_qty
|
local cntr_cell
|
-- SKU 找到适配的空料箱格
|
for _, empty_cell in ipairs( out_cntr.empty_cell_list ) do
|
if ( empty_cell.item_code == '' ) then
|
cntr_cell = {
|
qty = 0,
|
good_volume = 0,
|
good_weight = 0,
|
cntr_code = empty_cell.cntr_code,
|
cell_no = empty_cell.cell_no,
|
cell_type = out_cntr.cell_type,
|
}
|
nRet, Q = wms_cntr.Get_CntrCell_Goods_Qty( pac_cfg.ctd, out_cntr.cntr_good_weight, cntr_cell, sku )
|
if nRet ~= 0 then
|
return 1, Q
|
end
|
if ( Q > 0 ) then
|
if Q > qty then Q = qty end
|
|
sku.alloc_qty = sku.alloc_qty + Q
|
qty = qty - Q
|
if ( lua.equation( sku.alloc_qty, sku.qty ) ) then
|
sku.ok = true -- 表示已经全部分配了料箱
|
end
|
|
-- 把分配掉的si_qty个货品加到补料呼出的容器里
|
local cell_item = {
|
cntr_code = out_cntr.cntr_code,
|
cell_type = out_cntr.cell_type,
|
cell_no = empty_cell.cell_no,
|
item_code = sku.S_ITEM_CODE,
|
item_name = sku.S_ITEM_NAME,
|
wms_bn = "",
|
qty = Q,
|
sum_volume = Q*sku.volume,
|
sum_weight = Q*sku.weight,
|
weight = sku.weight,
|
volume = sku.volume,
|
sku = sku
|
}
|
empty_cell.item_code = sku.S_ITEM_CODE -- 说明该空料格已经有分配,需要后面的程序删除
|
table.insert( out_cntr.cell_list, cell_item )
|
out_cntr.cntr_good_weight = out_cntr.cntr_good_weight + cell_item.sum_weight
|
table.insert( sku.cntr_cell_list, cell_item )
|
|
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
|
if ( sku.ok ) then
|
break
|
end
|
end
|
end
|
end
|
end
|
|
return 0
|
end
|
|
-- 删除呼出容器中的empty_cell 列表中 名为 cell_no 的料格
|
function wms_pac.remove_empty_cell( cntr, cell_no )
|
local n
|
for n = 1, #cntr.empty_cell do
|
if (cntr.empty_cell[n].cell_no == cell_no ) then
|
table.remove( cntr.empty_cell, n )
|
return
|
end
|
end
|
end
|
|
-- SKU 根据 cell_type + Q (需要呼出料格数量) 进行排序 Q 大的前面
|
local function sku_sort( sku_a, sku_b )
|
-- A 排 B 前面
|
if sku_a.S_CELL_TYPE > sku_b.S_CELL_TYPE then
|
return false
|
elseif sku_a.S_CELL_TYPE == sku_b.S_CELL_TYPE then
|
return sku_a.Q > sku_b.Q
|
end
|
return true
|
end
|
|
--[[
|
合并可混箱的相同类型料格数量,
|
same_mixing_rule_item_list --> {{ cell_type ,need_cell_num , mixing_rule={} item_codes = {"X1","X2"} },...}
|
out_cell_item --> { cell_type ,need_cell_num , mixing_rule={}, item_code }
|
--]]
|
local function add_in_same_mixing_rule_item_list( ctd, same_mixing_rule_item_list, out_cell_item )
|
local find = false
|
|
for _, cell_item in ipairs( same_mixing_rule_item_list ) do
|
if cell_item.cell_type == out_cell_item.cell_type then
|
if not lua.isTableEmpty( out_cell_item.mixing_rule ) then
|
-- 判断是否相同混箱规则
|
nRet, find = wms_pac.sku_complies_with_mixing_rule ( ctd, out_cell_item.mixing_rule, cell_item.mixing_rule )
|
if ( nRet ~= 0 ) then
|
return 1, find
|
end
|
if find then
|
cell_item.need_cell_num = cell_item.need_cell_num + out_cell_item.need_cell_num
|
table.insert( cell_item.sku_list, out_cell_item.sku )
|
return 0
|
end
|
end
|
end
|
end
|
|
if not find then
|
local out_cntr = {
|
cell_type = out_cell_item.cell_type,
|
need_cell_num = out_cell_item.need_cell_num,
|
mixing_rule = out_cell_item.mixing_rule,
|
sku_list = {}
|
}
|
table.insert( out_cntr.sku_list, out_cell_item.sku )
|
table.insert( same_mixing_rule_item_list, out_cntr )
|
end
|
return 0
|
end
|
|
--[[
|
把货品分配到 呼出的料箱格列表 out_cntr_list
|
cntr_list/准备呼出的料箱 = {{ cntr_code,cntr_good_weight,cntr_mixing_rule = {} cell_type,empty_cell_list = {},,full = false,cell_list = {},...}
|
cntr_mixing_rule -- 料箱混料规则
|
item -- 入库单明细 item_list 中的一个元素
|
out_cntr_list -- 分配好的料格加入这个列表
|
注意:这里的 out_cntr_list 都是符合混箱规则的,空料格都可以分配
|
--]]
|
local function alloc_cntr( strLuaDEID, pac_cfg, cntr_list, item, out_cntr_list )
|
local nRet, strRetInfo
|
|
if pac_cfg == nil then
|
return 1, "alloc_cntr 函数中输入参数 pac_cfg 不能为 nil"
|
end
|
if item == nil then
|
return 1, "alloc_cntr 函数中输入参数 item 不能为 nil"
|
end
|
if cntr_list == nil then
|
return 1, "alloc_cntr 函数中输入参数 cntr_list 不能为 nil"
|
end
|
-- 如果货品已经分配完成不需要执行该函数
|
if item.ok then return 0 end
|
|
local cntr_cell = {}
|
local si_qty, qty
|
for _, cntr in ipairs( cntr_list ) do
|
-- 遍历呼出料箱中的空料格列表
|
for _, empty_cell in ipairs( cntr.empty_cell_list ) do
|
-- item_code 为空说明这个料格还没有被其它货品分配
|
if empty_cell.item_code == '' then
|
-- 料格初始化
|
cntr_cell = {
|
cntr_code = cntr.cntr_code,
|
cell_no = empty_cell.cell_no,
|
cell_type = cntr.cell_type,
|
good_volume = 0, -- 料格已经存放的货品体积累计值
|
good_weight = 0,
|
qty = 0,
|
wms_bn = ""
|
}
|
cntr_good_weight = cntr.cntr_good_weight
|
|
-- 计算一下料格能分配多少个货品 si_qty
|
nRet, si_qty = wms_cntr.Get_CntrCell_Goods_Qty( pac_cfg.ctd, cntr_good_weight, cntr_cell, item )
|
if ( nRet ~= 0 ) then
|
return 1, si_qty
|
end
|
-- 如果计算出来的可存储数量大于 item.qty
|
qty = item.qty - item.alloc_qty
|
if ( si_qty > qty ) then
|
si_qty = qty
|
end
|
-- si_qty 补料数量
|
if ( si_qty > 0 ) then
|
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,
|
wms_bn = "",
|
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( item.cntr_cell_list, cell_item )
|
table.insert( cntr.cell_list, cell_item )
|
cntr.cntr_good_weight = cntr.cntr_good_weight + cell_item.sum_weight
|
empty_cell.item_code = cell_item.item_code
|
|
if lua.isTableEmpty( cntr.cntr_mixing_rule ) then
|
local cntr_mixing_rule = {}
|
for _, attr in ipairs( pac_cfg.ctd.mixing_attrs ) do
|
cntr_mixing_rule[attr] = lua.Get_StrAttrValue( item[attr])
|
end
|
cntr.cntr_mixing_rule = cntr_mixing_rule
|
end
|
|
-- 更新容器对象里 N_ALLOC_CELL_NUM 数量
|
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
|
if item.ok then
|
goto reste_cntr_list
|
end
|
|
end
|
end
|
end
|
end
|
|
::reste_cntr_list::
|
-- 设置一下 cntr_list 中的空料格
|
local find
|
wms_pac.reset_empty_cell_info( cntr_list )
|
for _, cntr in ipairs( cntr_list ) do
|
if #cntr.cell_list > 0 then
|
find = false
|
for _, out_cntr in ipairs( out_cntr_list ) do
|
if cntr.cntr_code == out_cntr.cntr_code then
|
find = true
|
break
|
end
|
end
|
if not find then
|
table.insert( out_cntr_list, cntr )
|
end
|
end
|
end
|
return 0
|
end
|
|
--[[
|
把对应的货品分配到呼出的空料箱
|
same_cell_sum/相同料格汇总信息 = { cell_type ,need_cell_num , mixing_rule={} sku_list = {item_code,item_state,storer} }
|
cntr_list/呼出的料箱编码 ={{ cntr_code,cntr_good_weight,cell_type,empty_cell = {},,full = false,cell_list = {},...}
|
item_list/入库单明细
|
out_cntr_list
|
--]]
|
local function alloc_cntr_by_cell_same_sum( strLuaDEID, pac_cfg, cell_same_sum, cntr_list, item_list, out_cntr_list )
|
local nRet, strRetInfo
|
|
for _, sku in ipairs( cell_same_sum.sku_list ) do
|
for _, item in ipairs( item_list ) do
|
-- 定位到 入库单明细 这里的item
|
if item.S_ITEM_CODE == sku.item_code and item.S_ITEM_STATE == sku.item_state and item.S_STORER == sku.storer then
|
nRet, strRetInfo = alloc_cntr( strLuaDEID, pac_cfg, cntr_list, item, out_cntr_list )
|
if ( nRet ~= 0 ) then
|
return 1, strRetInfo
|
end
|
break
|
end
|
end
|
end
|
return 0
|
end
|
|
--[[
|
根据货品的料格类型呼出符合混箱规则的空料格
|
ctd -- 容器类型定义
|
str_loc_where -- 查询货位的条件
|
item -- 入库明细中的货品
|
out_cntr_list -- 呼出料箱格清单
|
--]]
|
local function empty_cell( strLuaDEID, pac_cfg, str_loc_where, item, out_cntr_list )
|
local nRet, strRetInfo
|
local mixing_condition = ''
|
|
local strTable = "TN_Container_Cell a LEFT JOIN TN_Container b ON a.S_CNTR_CODE = b.S_CODE " -- 联表
|
-- 如果有混箱规则,需要把容器中规则定义的属性取值
|
if ( pac_cfg.ctd.have_mixing_rule ) then
|
strTable = strTable.." LEFT JOIN TN_Container_Ext c ON a.S_CNTR_CODE = c.S_CNTR_CODE"
|
-- 获取 SKU 的混箱属性
|
for _, attr in ipairs( pac_cfg.ctd.mixing_attrs ) do
|
mixing_condition = mixing_condition.." AND c."..attr.." = '"..lua.Get_StrAttrValue( item[attr] ).."' "
|
end
|
end
|
local cell_type = item.S_CELL_TYPE
|
local strAttrs = "a.S_CNTR_CODE, a.S_CELL_NO, b.F_GOOD_WEIGHT" -- 查询字段
|
local strCondition = " b.S_CTD_CODE = '"..pac_cfg.ctd.ctd_code.."' AND b.S_SPEC = '"..cell_type.."' "..
|
" AND a.S_CNTR_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..")) "..
|
" AND a.N_EMPTY_FULL = 0 AND b.N_LOCK_STATE = 0 AND b.C_ENABLE = 'Y' AND b.N_EMPTY_FULL < 2 AND b.C_FORCED_FILL = 'N'"..
|
" AND a.S_STATE <> 'Abnormal'"..mixing_condition
|
-- 如果要控制料箱总的载重
|
if ( pac_cfg.ctd.check_capacity ) then
|
strCondition = strCondition.." AND b.F_GOOD_WEIGHT < "..pac_cfg.ctd.load_capacity
|
end
|
--
|
nRet, strRetInfo = mobox.queryMultiTable(strLuaDEID, strAttrs, strTable, 1000, strCondition )
|
if ( nRet ~= 0 ) then
|
return 2, "查询【容器料格】信息失败! " .. strRetInfo
|
end
|
if ( strRetInfo == '' ) then
|
return 0
|
end
|
local cntr_cell_attr_set = json.decode(strRetInfo)
|
|
for _, cntr_cell_attr in ipairs( cntr_cell_attr_set ) do
|
-- cntr_cell 用于计算数量用
|
local cntr_cell = {
|
cntr_code = cntr_cell_attr[1],
|
cell_no = cntr_cell_attr[2],
|
cell_type = cell_type,
|
wms_bn = "", good_volume = 0, good_weight = 0, qty = 0
|
}
|
cntr_good_weight = lua.Get_NumAttrValue( cntr_cell_attr[3] )
|
|
-- 计算一下料格能分配多少个货品 si_qty
|
nRet, si_qty = wms_cntr.Get_CntrCell_Goods_Qty( pac_cfg.ctd, cntr_good_weight, cntr_cell, item )
|
if ( nRet ~= 0 ) then
|
return 1, si_qty
|
end
|
-- 如果计算出来的可存储数量大于 item.qty
|
qty = item.qty - item.alloc_qty
|
if ( si_qty > qty ) then
|
si_qty = qty
|
end
|
-- si_qty 补料数量
|
if ( si_qty > 0 ) then
|
item.alloc_qty = item.alloc_qty + si_qty
|
if ( lua.equation( item.alloc_qty, item.qty) ) then
|
item.ok = true -- 表示已经全部分配了料箱
|
end
|
|
-- 把分配掉的si_qty个货品加到补料呼出的容器里
|
weight = lua.Get_NumAttrValue( item.F_WEIGHT )
|
volume = lua.Get_NumAttrValue( item.F_VOLUME )
|
|
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,
|
wms_bn = "",
|
qty = si_qty,
|
sum_volume = si_qty*volume,
|
sum_weight = si_qty*weight,
|
weight = weight,
|
volume = volume,
|
sku = item
|
}
|
wms_pac.put_cell_item_to_out_cntr_list( out_cntr_list, cntr_good_weight, cell_item, item.mixing_rule )
|
table.insert( item.cntr_cell_list, cell_item )
|
|
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
|
if item.ok then
|
return 0
|
end
|
end
|
end
|
return 0
|
end
|
|
-- 计算 SKU 需要多少个空料格 Q
|
local function set_sku_Q_value( ctd, item_list )
|
local nRet, strRetInfo
|
|
local cntr_cell = {
|
cntr_code = "",
|
cell_no = "",
|
wms_bn = "",
|
good_volume = 0,
|
cell_type = "",
|
good_weight = 0,
|
qty = 0
|
}
|
local cell_max_qty -- 料格数量
|
local x_qty, qty
|
for _, sku in ipairs( item_list ) do
|
if not sku.ok then
|
-- 计算 SKU 需要多少个空料格
|
-- 获取一个料格能分配多少给 SKU
|
qty = sku.qty - sku.alloc_qty
|
cntr_cell.cell_type = sku.S_CELL_TYPE
|
nRet, cell_max_qty = wms_cntr.Get_CntrCell_Goods_Qty( ctd, 0, cntr_cell, sku )
|
if nRet ~= 0 then
|
return nRet, cell_max_qty
|
end
|
if cell_max_qty <= 0 then
|
return 1, "SKU'"..sku.S_ITEM_CODE.."'在计算料格转载最大数量是失败,返回数量 <= 0"
|
end
|
Q = math.floor( qty/cell_max_qty)
|
-- 余量
|
x_qty = qty - Q*cell_max_qty
|
if ( lua.equation( 0, x_qty ) == false ) then
|
Q = Q + 1
|
end
|
sku.Q = Q
|
else
|
sku.Q = 0
|
end
|
end
|
return 0
|
end
|
|
local function get_same_mixing_rule_cntr_list( ctd, item_list )
|
local nRet, strRetInfo
|
local same_mixing_rule_cntr_list = {}
|
|
for _, sku in ipairs( item_list ) do
|
-- 合并相同 cell_type 及 混箱规则的SKU这些货品可以一起呼叫料箱
|
if not sku.ok then
|
local out_cell_item = {
|
cell_type = sku.S_CELL_TYPE,
|
need_cell_num = sku.Q,
|
mixing_rule = sku.mixing_rule,
|
sku = { item_code = sku.S_ITEM_CODE, item_state = sku.S_ITEM_STATE, storer = sku.S_STORER }
|
}
|
nRet, strRetInfo = add_in_same_mixing_rule_item_list( ctd, same_mixing_rule_cntr_list, out_cell_item )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
end
|
end
|
return 0, same_mixing_rule_cntr_list
|
end
|
|
-- 从容器表查出 num 个空料箱(所有料格都空)分配
|
-- cell_same_sum 相同混箱规则需要的料格定义, num -- 需要的料箱数量, str_loc_where -- 查货位的条件
|
-- out_cntr_list -- 呼出料箱料格结果
|
local function query_empty_cntr_to_alloc( strLuaDEID, pac_cfg, item_list, cell_same_sum, num, str_loc_where, out_cntr_list )
|
local n, nRet, data_objs, strRetInfo, data_attrs
|
local cntr_list = {}
|
|
-- 注: N_EMPTY_FULL = 0 表示空箱 N_LOCK_STATE = 0 表示料格没锁 N_ALLOC_CELL_NUM = 0 表示没预分配
|
-- **** N_ALLOC_CELL_NUM 这里需要再思考一下
|
local strCondition = "S_CTD_CODE = '"..pac_cfg.ctd.ctd_code.."' AND S_SPEC = '"..cell_same_sum.cell_type.."' AND N_EMPTY_FULL = 0 AND N_LOCK_STATE = 0 AND N_ALLOC_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..")) "
|
nRet, data_objs = m3.QueryDataObject3( strLuaDEID, "Container", strCondition, "",num)
|
if (nRet ~= 0) then
|
return 2, "查询容器失败! "..data_objs
|
end
|
if ( data_objs ~= '' ) then
|
for n = 1, #data_objs do
|
data_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
|
local out_cntr = {
|
cntr_code = data_attrs.S_CODE,
|
cntr_good_weight = 0,
|
cell_type = cell_same_sum.cell_type,
|
empty_cell_list = {},
|
full = false,
|
cell_list = {}
|
}
|
table.insert( cntr_list, out_cntr )
|
end
|
nRet, strRetInfo = wms_pac.set_out_cntr_empty_cell( strLuaDEID, cntr_list )
|
if ( nRet ~= 0 ) then
|
return 1, strRetInfo
|
end
|
-- 把对应的货品分配到呼出的空料箱,把料箱加入呼出列表 out_cntr_list
|
nRet, strRetInfo = alloc_cntr_by_cell_same_sum( strLuaDEID, pac_cfg, cell_same_sum, cntr_list, item_list, out_cntr_list )
|
if ( nRet ~= 0 ) then
|
return 1, strRetInfo
|
end
|
end
|
return 0
|
end
|
--[[
|
step2.0 获取空料格
|
--]]
|
function wms_pac.get_out_cntr_list_dmg( strLuaDEID, pac_cfg, item_list, out_cntr_list )
|
local nRet, strRetInfo, strCondition, strOrder
|
local n, nCount
|
local str_loc_where = ''
|
|
-- step1 输入参数判断
|
if ( pac_cfg.wh_code == nil or pac_cfg.wh_code == '' ) then
|
return 1, "输入参数错误, wh_code 必须有值"
|
end
|
-- 这里要加一下巷道限制 ******
|
str_loc_where = "S_WH_CODE = '"..pac_cfg.wh_code.."'"
|
|
local ctd_code = pac_cfg.ctd.ctd_code
|
if ( ctd_code == nil or ctd_code == '' ) then
|
return 1, "输入参数错误, pac_cfg 中 ctd.ctd_code 必须有值"
|
end
|
|
-- step2 数据准备
|
-- 统计入库 sku 需要多少个料格
|
nRet, strRetInfo = set_sku_Q_value( pac_cfg.ctd, item_list )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
-- SKU 根据 cell_type + Q (需要呼出料格数量) 进行排序 Q 大的前面
|
table.sort( item_list, sku_sort )
|
|
-- 遍历需要入库的货品清单,把相同入库条件的货品需要呼出的料箱数量合并,确定是否整个料箱都是空的料箱先呼出
|
-- 先呼出整个料箱都是空的料箱,目的是减少出入库料箱数量
|
local same_mixing_rule_cntr_list
|
nRet, same_mixing_rule_cntr_list = get_same_mixing_rule_cntr_list( pac_cfg.ctd, item_list )
|
if ( nRet ~= 0 ) then
|
return 1, same_mixing_rule_cntr_list
|
end
|
|
-- step3
|
-- 先把可以进相同混箱规则料箱的货品 SUM 在一起,呼出全空的料箱(每个料格都是空),尽量减少搬运次数
|
local cell_def, data_attrs, data_objs, cell_same_sum
|
local cntr_list
|
|
for _, cell_same_sum in ipairs( same_mixing_rule_cntr_list ) do
|
nRet, cell_def = wms_cntr.Get_CTD_GridDef( pac_cfg.ctd, cell_same_sum.cell_type )
|
if nRet ~= 0 then
|
return 1, cell_def
|
end
|
-- 如果需要的料格数量小于 一个空料箱的料格 不执行下面的呼出
|
if cell_same_sum.need_cell_num >= cell_def.box_num then
|
num = math.floor( cell_same_sum.need_cell_num/cell_def.box_num )
|
-- 从容器表找到合适的料箱(数量=num)分配给 item_list
|
nRet, strRetInfo = query_empty_cntr_to_alloc( strLuaDEID, pac_cfg, item_list, cell_same_sum, num, str_loc_where, out_cntr_list )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
end
|
end
|
|
local pac_is_ok = wms_pac.item_list_is_all_ok( item_list )
|
|
-- step 4 查找有相同混箱规则的且未满有货的料格
|
if not pac_is_ok then
|
for _, item in ipairs( item_list ) do
|
if not item.ok then
|
-- 根据货品的适配料格类型呼出空料格
|
for _, cntr in ipairs( out_cntr_list ) do
|
nRet, strRetInfo = wms_pac.pre_alloc_sku_to_out_cntr( strLuaDEID, pac_cfg, item, cntr )
|
if ( nRet ~= 0 ) then
|
return 1, strRetInfo
|
end
|
if item.ok then
|
break
|
end
|
end
|
end
|
end
|
end
|
|
pac_is_ok = wms_pac.item_list_is_all_ok( item_list )
|
-- step 5 查找全空料箱装载剩余没分配料格的货品
|
if not pac_is_ok then
|
-- 进一步设置一下货品需要的料格数 Q
|
nRet, strRetInfo = set_sku_Q_value( pac_cfg.ctd, item_list )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
-- SKU 根据 cell_type + Q (需要呼出料格数量) 进行排序 Q 大的前面
|
table.sort( item_list, sku_sort )
|
nRet, same_mixing_rule_cntr_list = get_same_mixing_rule_cntr_list( pac_cfg.ctd, item_list )
|
if ( nRet ~= 0 ) then
|
return 1, same_mixing_rule_cntr_list
|
end
|
|
for _, cell_same_sum in ipairs( same_mixing_rule_cntr_list ) do
|
nRet, cell_def = wms_cntr.Get_CTD_GridDef( pac_cfg.ctd, cell_same_sum.cell_type )
|
if nRet ~= 0 then
|
return 1, cell_def
|
end
|
num = math.floor( cell_same_sum.need_cell_num/cell_def.box_num )
|
if ( cell_same_sum.need_cell_num-num*cell_def.box_num ) > 0 or num == 0 then
|
num = num + 1
|
end
|
-- 从容器表找到合适的料箱(数量=num)分配给 item_list
|
nRet, strRetInfo = query_empty_cntr_to_alloc( strLuaDEID, pac_cfg, item_list, cell_same_sum, num, str_loc_where, out_cntr_list )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
end
|
end
|
return 0
|
end
|
|
--[[
|
step1.1 获取补料料格
|
--]]
|
function wms_pac.get_replenishment_cntr_list( strLuaDEID, pac_cfg, item_list )
|
local nRet, strRetInfo, strCondition, strOrder
|
local n, nCount
|
local str_loc_where = ''
|
local supplement_cntr_list = {}
|
|
-- 输入参数判断
|
if ( pac_cfg.wh_code == nil or pac_cfg.wh_code == '' ) then
|
return 1, "输入参数错误, wh_code必须有值"
|
end
|
str_loc_where = "S_WH_CODE = '"..pac_cfg.wh_code.."'"
|
|
local ctd_code = pac_cfg.ctd.ctd_code
|
if ( ctd_code == nil or ctd_code == '' ) then
|
return 1, "输入参数错误, pac_cfg 中 ctd.ctd_code 必须有值"
|
end
|
|
-- 组织匹配料格的查询条件
|
local si_match_attrs = pac_cfg.ctd.si_match_attrs or {}
|
if ( type(si_match_attrs) ~= "table" ) then
|
return 1, "输入参数错误, pac_cfg.ctd.si_match_attrs 必须是 table 类型!"
|
end
|
-- 匹配属性要加上 S_ITEM_CODE, S_STRORER, S_ITEM_STATE
|
table.insert( si_match_attrs, "S_STORER" )
|
table.insert( si_match_attrs, "S_ITEM_CODE" )
|
table.insert( si_match_attrs, "S_ITEM_STATE" )
|
|
local ret_attr
|
local cntr_cell = {}
|
local si_qty, qty, cntr_good_weight
|
|
-- 确定匹配料格时查询顺序
|
strOrder = ''
|
local si_match_order = lua.Get_StrAttrValue( pac_cfg.ctd.si_match_order )
|
if ( si_match_order == "Last_Entry_Batch" ) then
|
strOrder = "a.S_WMS_BN DESC"
|
elseif ( si_match_order == "QTY_Desc" ) then
|
strOrder = "a.F_QTY DESC"
|
elseif ( si_match_order == "QTY_Asc" ) then
|
strOrder = "a.F_QTY Asc"
|
end
|
|
-- 查询匹配的数量
|
local si_cntr_num = lua.Get_NumAttrValue( pac_cfg.ctd.si_cntr_num )
|
if ( si_cntr_num == 0 ) then si_cntr_num = 1000 end
|
|
strTable = "TN_Container_Cell a LEFT JOIN TN_Container b ON a.S_CNTR_CODE = b.S_CODE " -- 联表
|
-- 如果有混箱规则,需要把容器中规则定义的属性取值
|
if ( pac_cfg.ctd.have_mixing_rule ) then
|
strTable = strTable.." LEFT JOIN TN_Container_Ext c ON a.S_CNTR_CODE = c.S_CNTR_CODE"
|
end
|
|
strAttrs = "a.S_CNTR_CODE, a.S_CELL_NO, a.S_WMS_BN, a.F_GOOD_VOLUME, b.S_SPEC, b.F_GOOD_WEIGHT, a.F_GOOD_WEIGHT, a.F_QTY" -- 查询字段
|
local ext_attr_index = 8
|
if ( pac_cfg.ctd.have_mixing_rule ) then
|
for _, attr in ipairs( pac_cfg.ctd.mixing_attrs ) do
|
strAttrs = strAttrs..",c."..attr
|
end
|
end
|
|
local cntr_max_weight = pac_cfg.ctd.load_capacity
|
local match_condition, str_value, weight, volume
|
local si_match_attrs_count = #si_match_attrs
|
local cntr_mixing_rule
|
|
for n = 1, #item_list do
|
match_condition = ""
|
for i = 1, si_match_attrs_count do
|
str_value = item_list[n][si_match_attrs[i]]
|
if ( str_value == nil ) then
|
return 1, "容器类型定义'"..pac_cfg.ctd.ctd_code.."' matching_attrs --> "..si_match_attrs[i].." 没有在 item_list 中定义!"
|
end
|
match_condition = match_condition.." AND a."..si_match_attrs[i].." = '"..str_value.."' "
|
end
|
|
-- 查询出仓库里同一货品最近批次号并且未满的料格, 查 Container_Cell 表
|
-- 注: N_EMPTY_FULL = 1 表示料格有货未满格 N_LOCK_STATE = 0 表示料格没锁
|
-- a.S_STATE <> 'Abnormal' 料格有异常
|
strCondition = "b.S_CTD_CODE = '"..ctd_code.."' AND a.S_CNTR_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..")) "..
|
" AND a.C_FORCED_FILL = 'N' AND a.N_EMPTY_FULL = 1 AND b.N_LOCK_STATE = 0 AND b.C_ENABLE = 'Y' AND b.N_EMPTY_FULL < 2 AND b.C_FORCED_FILL = 'N'"..
|
" AND a.S_STATE <> 'Abnormal'"..match_condition
|
-- 如果要控制料箱总的载重
|
if ( pac_cfg.ctd.check_capacity ) then
|
strCondition = strCondition.." AND b.F_GOOD_WEIGHT < "..cntr_max_weight
|
end
|
--
|
nRet, strRetInfo = mobox.queryMultiTable(strLuaDEID, strAttrs, strTable, si_cntr_num, strCondition )
|
if ( nRet ~= 0 ) then return 2, "查询【容器料格】信息失败! " .. strRetInfo end
|
if ( strRetInfo ~= '' ) then
|
ret_attr = json.decode(strRetInfo)
|
|
if ( si_cntr_num == 1 ) then
|
-- 只是匹配一个补料料箱,一般就是找最近入库批次的料箱
|
cntr_cell.cntr_code = ret_attr[1][1]
|
cntr_cell.cell_no = ret_attr[1][2]
|
cntr_cell.wms_bn = ret_attr[1][3]
|
cntr_cell.good_volume = lua.StrToNumber( ret_attr[1][4] ) -- 料格已经存放的货品体积累计值
|
cntr_cell.cell_type = ret_attr[1][5] -- 料格类型 A/B/C/D/E
|
cntr_good_weight = lua.StrToNumber( ret_attr[1][6] ) -- 容器当前存储货品重量
|
cntr_cell.good_weight = lua.StrToNumber( ret_attr[1][7] )
|
cntr_cell.qty = lua.StrToNumber( ret_attr[1][8] )
|
-- 获取料箱混箱规则属性
|
cntr_mixing_rule = {}
|
for i, attr in ipairs( pac_cfg.ctd.mixing_attrs ) do
|
cntr_mixing_rule[attr] = lua.Get_StrAttrValue( ret_attr[1][ext_attr_index+i])
|
end
|
|
-- 计算一下料格能分配多少个货品 si_qty
|
nRet, si_qty = wms_cntr.Get_CntrCell_Goods_Qty( pac_cfg.ctd, cntr_good_weight, cntr_cell, item_list[n] )
|
|
if ( nRet ~= 0 ) then
|
return 1, si_qty
|
end
|
-- 如果计算出来的可存储数量大于 item.qty
|
qty = item_list[n].qty - item_list[n].alloc_qty
|
if ( si_qty > qty ) then
|
si_qty = qty
|
end
|
-- si_qty 补料数量
|
if ( si_qty > 0 ) then
|
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个货品加到补料呼出的容器里
|
weight = lua.Get_NumAttrValue( item_list[n].F_WEIGHT )
|
volume = lua.Get_NumAttrValue( item_list[n].F_VOLUME )
|
|
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,
|
wms_bn = "",
|
qty = si_qty,
|
sum_volume = si_qty*volume,
|
sum_weight = si_qty*weight,
|
weight = weight,
|
volume = volume,
|
sku = item_list[n]
|
}
|
wms_pac.put_cell_item_to_out_cntr_list( supplement_cntr_list, cntr_good_weight, cell_item, cntr_mixing_rule )
|
table.insert( item_list[n].cntr_cell_list, cell_item )
|
end
|
else
|
return 1, "代码未完成..."
|
end
|
end
|
::continue::
|
end
|
|
return 0, supplement_cntr_list
|
end
|
|
--[[
|
料箱料格类型根据 SKU 中的 S_CELL_TYPE 获取
|
输入参数: pac_cfg = {
|
wh_code, area_code 仓库,库区编码
|
station 站台
|
bs_type 来源类型:入库单、入库波次
|
bs_no 来源单号
|
aisle -- 可用巷道 'A01',"A02",... 字符串
|
cntr_out_op_def = "料箱出库", --空料箱出库的作业定义
|
cntr_back_op_def = "货品入库" --料箱回库的主业定义
|
|
-- 容器类型定义
|
ctd = {
|
check_capacty = false/true, ---是否检测整箱载重),
|
load_capacity = 50, --料箱最大载重
|
si_enable = false/true, -- 是否启用补料
|
si_match_attrs = {"S_ITEM_CODE","XX",...} -- 这些属性一致的可以进行补料
|
si_match_order = "Last_Entry_Batch/QTY_Desc/QTY_Asc" -- 可以为空
|
si_cntr_num = 0/1 -- 0 不限制所以可以补料的料箱优先补料, 1 -- 补一个料箱
|
grid_box_def = { { cell_type = "A",volume = 72000, box_num = 1,load_capacity=12},...}
|
have_mixing_rule = false/true true 表示有混箱规则
|
mixing_attrs = {"A","B"} -- 这些属性一样的可以放一个料箱
|
}
|
}
|
item_list -- 需要预分配料箱的货品列表(注意这里入库的货品的容器类型都一样)
|
|
pac_list, pac_detail_list 为返回值
|
--]]
|
function wms_pac.Pre_Alloc_Cntr_DMG( strLuaDEID, pac_cfg, item_list )
|
local nRet, strRetInfo, n
|
local wh_code, station, bs_type, bs_no
|
local ctd_code
|
local sku_count = #item_list
|
|
local supplement_cntr_list = {}
|
local out_cntr_list = {}
|
-- step0: 输入参数校验,及初始化
|
if ( sku_count == 0 ) then
|
return 0
|
end
|
|
if ( pac_cfg == nil or type( pac_cfg ) ~= "table" ) then
|
return 2, "Pre_Alloc_Cntr_DMG 函数输入参数错误: pac_cfg 必须有值,必须是 table 类型"
|
end
|
|
wh_code = lua.Get_StrAttrValue( pac_cfg.wh_code )
|
if ( wh_code == '' ) then
|
return 2, "Pre_Alloc_Cntr_DMG 函数输入参数错误: pac_cfg 参数中的 wh_code 必须有值!"
|
end
|
|
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_DMG 算法只适合 Cell_Box 类型的容器进行分配, pac_cfg中的参数 ctd_code 错误!"
|
end
|
|
-- step1 计算补料呼出料箱
|
-- 是否启用补料呼出
|
local have_si_empty_cell = false -- 补料呼出料箱中是否还有空料格
|
local pac_is_ok = false -- 预分配操作已经完成
|
|
if ( pac_cfg.ctd.si_enable ) then
|
-- step1.1 容器定义中允许补料箱
|
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
|
-- step1.2 设置补料料箱中的空料格列表
|
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
|
|
-- step2 遍历item_list计算适配空料箱
|
if not pac_is_ok then
|
-- 继续呼出料箱
|
nRet, strRetInfo = wms_pac.get_out_cntr_list_dmg( strLuaDEID, pac_cfg, item_list, out_cntr_list )
|
if ( nRet ~= 0 ) then
|
return 2, strRetInfo
|
end
|
end
|
|
-- step3 检查是否所以货品都已经预分配了料箱,
|
local msg_list = {} -- 保存无法分配料格的货品数量
|
for _, sku in ipairs( item_list ) do
|
if ( sku.ok == false ) then
|
local qty = sku.qty-sku.alloc_qty
|
local msg = "系统没有匹配到货品编码 = '"..sku.S_ITEM_CODE.."'的适配料箱进行预分配, 货品的适配料格类型 = '"..sku.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_list
|
end
|
|
return wms_pac
|