--[[
|
版本: Version 1.0
|
创建日期: 2025-1-26
|
创建人: HAN
|
|
功能:
|
和出库相关的操作,如配盘
|
|
-- Shipping_Order_CheckState 检查【发货单明细】 配盘是否全部完成,如果全部完成 N_B_STATE = 1
|
** Creat_Distribution 创建配盘及配盘明细(适合手工配盘)
|
-- Check_Distribution_WholeOut 检测配盘是否为整出
|
-- Get_Outbound_Detail_list 根据输入的出库单编码获取 出库单明细列表,oo_no_set 是一个出库单编码数组,如["OO010","OO012"]
|
** Split_Distribution_CNTR_Detail 波次合并后产生的 配盘明细 批分到每个出库单明细
|
** Distribution_Procedure 根据货品列表系统自动生成配盘和配盘明细,条件是根据货品编码 item_code 确定货品,
|
根据批次号顺序配盘,批次号小的优先出
|
-- Creat_Distribution_list 创建配盘及配盘明细数据对象
|
-- Sum_outbound_detail 把出库单明细中的 item 加入出库明细汇总链表
|
-- Distribution_CNTR_Detail_PostProcess 配盘明细的后处理程序(分拣出库后对数据的处理)
|
** 标记的是主要函数
|
|
更改说明:
|
V2.0 HAN 20241122 Distribution_Procedure 增加全属性覆盖,条件判断改进
|
--]]
|
|
wms_cntr = require ("wms_container")
|
wms_wh = require ("wms_wh")
|
|
local wms_out = {_version = "0.1.1"}
|
|
-- 检查 发货单明细 配盘是否全部完成,如果全部完成 N_B_STATE = 1
|
function wms_out.Shipping_Order_CheckState ( strLuaDEID, shipping_no )
|
local n, nRet, strRetInfo
|
|
-- 获取【发货单明细】
|
local strCondition = "S_SHIPPING_NO = '"..shipping_no.."'"
|
local strOrder = ""
|
local data_objs
|
local distribution_finish = true
|
|
nRet, data_objs = m3.QueryDataObject( strLuaDEID, "Shipping_Detail", strCondition, strOrder )
|
if (nRet ~= 0) then return 1, "获取【Shipping_Detail】信息失败! " .. data_objs end
|
local obj_attrs
|
local qty, acc_d_qty
|
|
for n = 1, #data_objs do
|
obj_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
|
qty = lua.StrToNumber( obj_attrs.F_QTY )
|
acc_d_qty = lua.StrToNumber( obj_attrs.F_ACC_D_QTY )
|
if ( qty > acc_d_qty ) then
|
distribution_finish = false
|
break
|
end
|
end
|
if ( distribution_finish ) then
|
local strUpdateSql = "N_B_STATE = 1"
|
strCondition = "S_NO = '"..shipping_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Shipping_Order", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then return 1, "更新【发货单】信息失败!"..strRetInfo end
|
end
|
return 0
|
end
|
|
-- 检测配盘是否为整出, 判断的依据是 CG_Detail中的 qty - 配盘明细中的qty 后的值全部为 0
|
-- distribution_id 【配盘】对象标识
|
-- nRet = 0 程序执行无错误 否则 > 0. strRetInfo = "yes" 表示是整拖出
|
function wms_out.Check_Distribution_WholeOut( strLuaDEID, distribution_cntr )
|
local nRet, strRetInfo, n, i
|
|
if ( distribution_id == nil or type(distribution_cntr) ~= 'table' ) then
|
return 1, "wms_out.Check_Distribution_WholeOut 函数中 distribution 不能为空,必须为table!"
|
end
|
|
-- 获取【配盘明细】
|
local data_objects
|
local strCondition = "S_DC_NO = '"..distribution_cntr.dc_no.."'"
|
nRet, data_objects = m3.QueryDataObject(strLuaDEID, "Distribution_CNTR_Detail", strCondition, "S_ITEM_CODE" )
|
if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objects end
|
if ( data_objects == '') then return 0, "no" end
|
local dc_detail = {}
|
for n = 1, #data_objects do
|
dc_detail[n] = m3.KeyValueAttrsToObjAttr(data_objects[n].attrs)
|
end
|
|
-- 获取【CG_Detail】
|
local strCondition = "S_CNTR_CODE = '"..distribution_cntr.cntr_code.."'"
|
nRet, data_objects = m3.QueryDataObject(strLuaDEID, "CG_Detail", strCondition, "S_ITEM_CODE" )
|
if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objects end
|
if ( data_objects == '') then return 0, "no" end
|
local obj_attrs
|
|
if ( #data_objects > #dc_detail ) then
|
-- 如果容器中的货品条数 > 配盘明细 肯定不是整托出
|
return 0, "no"
|
end
|
|
-- 遍历 容器货品明细 判断:cg_detail.qty - dc_detail.qty = 0
|
local cg_detail_qty, dc_detail_qty
|
local count = #dc_detail
|
for n = 1, #data_objects do
|
obj_attrs = m3.KeyValueAttrsToObjAttr(data_objects[n].attrs)
|
cg_detail_qty = lua.StrToNumber( obj_attrs.F_QTY )
|
-- 从【Distribution_CNTR_Detail】找到 cg_detial.S_ID 相同的 配盘明细
|
for i = 1, count do
|
if (dc_detail[i].G_CG_DETAIL_ID == data_objects[n].id) then
|
dc_detail_qty = lua.StrToNumber( dc_detail[i].F_QTY )
|
if ( cg_detail_qty > dc_detail_qty ) then
|
-- 如果容器货品中的数量大于本次配盘出库数量,说明出不完,不是整托出
|
return 0, "no"
|
end
|
break
|
end
|
end
|
end
|
return 0, "yes"
|
end
|
|
--[[
|
创建配盘及配盘明细, 用于手工配盘
|
输入参数 distribution_info -- 配盘信息,是一个table,格式如下
|
{
|
bs_type = "Shipping_Ordre", -- 来源类型(发货单/出库单)
|
bs_no = "shipping_no", -- 来源单号
|
bs_row_no = bs_row_no, -- 来源单行号
|
cntr_code = "", -- 容器号
|
loc_code = "", -- 容器来源货位信息
|
cg_detail_id = "xxxx", -- CG_Detail 中记录标识 S_ID
|
item_code = "", -- 物料编码
|
batch_no = "", -- 批次号
|
serial_no = "", -- 系列号
|
qty = 1, -- 配盘数量
|
loc_code = loc_code, -- 容器所在货位
|
exit_area_code = area_code, -- 出库口库区编码
|
exit_loc_code = ""
|
urgent_outbound = false -- 是否紧急出库
|
}
|
--]]
|
-- 返回值 nRet = 0 表示成功配盘 1 -- 表示业务流程不许可 2 -- 程序错误
|
function wms_out.Creat_Distribution( strLuaDEID, distribution_info )
|
local nRet, strRetInfo, strErr
|
|
-- step1 判断一下是否已经存在配盘
|
-- 查找 容器编码 = cntr_code 并且 状态=0,1,2 的配盘容器
|
local distribution_cntr
|
|
-- 输入参数检查,一些关键的属性必须有值
|
if ( distribution_info.cntr_code == nil or distribution_info.cntr_code == '') then
|
return 1, "输入的配盘信息中必须有 cntr_code !"
|
end
|
if ( distribution_info.bs_type == nil or distribution_info.bs_type == '' ) then
|
return 1, "输入的配盘信息中必须有 bs_type !"
|
end
|
if ( distribution_info.bs_no == nil or distribution_info.bs_no == '' ) then
|
return 1, "输入的配盘信息中必须有 bs_no !"
|
end
|
if ( distribution_info.cg_detail_id == nil or distribution_info.cg_detail_id == '' ) then
|
return 1, "输入的配盘信息中必须有 cg_detail_id !"
|
end
|
if ( distribution_info.loc_code == nil or distribution_info.loc_code == '' ) then
|
return 1, "输入的配盘信息中必须有 loc_code !"
|
end
|
local cntr_code = distribution_info.cntr_code
|
local loc
|
nRet, loc = wms_wh.GetLocInfo( distribution_info.loc_code )
|
if ( nRet ~= 0 ) then return 1, '获取货位信息失败! '..distribution_info.loc_code end
|
|
local strCondition = "S_CNTR_CODE = '"..distribution_info.cntr_code.."' AND N_B_STATE >= 0 AND N_B_STATE <= 3"
|
nRet, distribution_cntr = m3.GetDataObjByCondition( strLuaDEID, "Distribution_CNTR", strCondition )
|
-- nRet = 0 表示配盘已经存在
|
local b_have_sanme_cg_detail = false
|
local distribution_detail = {}
|
if (nRet == 0) then
|
if ( distribution_cntr.b_state ~= 0 ) then
|
return 1, "容器号 = '"..distribution_info.cntr_code.."' 的容器已经配盘完成不能继续配盘!"
|
end
|
|
-- 进一步判断配盘明细里是否已经存在 该 CG_Detail ID相同的配货信息(发货单一样),如果有数量累计即可,不需要另外创建
|
strCondition = "S_DC_NO = '"..distribution_cntr.dc_no.."' AND G_CG_DETAIL_ID = '"..distribution_info.cg_detail_id.."'"
|
strCondition = strCondition.." AND S_BS_TYPE = '"..distribution_info.bs_type.."' AND S_BS_NO = '"..distribution_info.bs_no.."'"
|
nRet, distribution_detail = m3.GetDataObjByCondition( strLuaDEID,"Distribution_CNTR_Detail", strCondition )
|
if (nRet == 0) then
|
b_have_sanme_cg_detail = true
|
elseif ( nRet > 1 ) then
|
return 1, "在检查[配盘明细]是否在时失败! " .. distribution_detail
|
end
|
|
-- 如果有紧急配盘,需要把配盘业务状态设置为 = 1(配盘完成)
|
if ( distribution_info.urgent_outbound ) then
|
-- 检查一下是否为整出
|
nRet, strRetInfo = wms_out.Check_Distribution_WholeOut( strLuaDEID, distribution_cntr )
|
if ( nRet ~= 0 ) then return nRet, strRetInfo end
|
|
strCondition = "S_ID = '"..distribution_cntr.id.."'"
|
local strSetAttr = "N_B_STATE = 1, S_B_STATE = '配盘完成' "
|
if ( strRetInfo == "yes" ) then
|
-- 说明是整个容器的货品都出库
|
strSetAttr = strSetAttr..", C_WHOLE_OUT = 'Y'"
|
end
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Distribution_CNTR", strCondition, strSetAttr )
|
if ( nRet ~= 0 ) then return 1, "updateDataAttrByCondition(Distribution_CNTR)失败"..strRetInfo end
|
end
|
|
elseif ( nRet == 1 ) then
|
-- step2 如果配盘不存在 创建配盘
|
distribution_cntr = m3.AllocObject(strLuaDEID, "Distribution_CNTR")
|
distribution_cntr.cntr_code = cntr_code
|
distribution_cntr.wh_code = loc.wh_code
|
distribution_cntr.area_code = loc.area_code
|
distribution_cntr.loc_code = loc.code
|
distribution_cntr.exit_area_code = distribution_info.exit_area_code
|
distribution_cntr.exit_loc_code = distribution_info.exit_loc_code
|
|
-- 如果有紧急配盘,需要把配盘业务状态设置为 = 1(配盘完成)
|
if ( distribution_info.urgent_outbound ) then
|
-- 检查一下是否为整出
|
nRet, strRetInfo = wms_out.Check_Distribution_WholeOut( strLuaDEID, distribution_cntr )
|
if ( nRet ~= 0 ) then return nRet, strRetInfo end
|
|
distribution_cntr.b_state = 1
|
distribution_cntr.b_state_name = "配盘完成" -- 这地方要改成从字典获取
|
if ( strRetInfo == "yes" ) then
|
distribution_cntr.whole_out = 'Y'
|
end
|
end
|
|
nRet, distribution_cntr = m3.CreateDataObj( strLuaDEID, distribution_cntr )
|
if ( nRet ~= 0 ) then return 1, '创建【配盘】对象失败!'..distribution_cntr end
|
|
else
|
return 1, "GetDataObjByCondition失败! "..distribution_cntr
|
end
|
|
local dc_no = distribution_cntr.dc_no -- 获取配盘号
|
|
-- step3 创建【配盘明细/Distribution_CNTR_Detail】
|
-- 获取 CG_Detail 信息
|
if ( b_have_sanme_cg_detail ) then
|
-- 【配盘明细】中已经存在相同的 CG_Detail, 更新数量
|
local strSetSQL = "F_QTY = F_QTY + ".. distribution_info.qty
|
strCondition = "S_DC_NO = '"..distribution_cntr.dc_no.."' AND G_CG_DETAIL_ID = '"..distribution_info.cg_detail_id.."'"
|
strCondition = strCondition.." AND S_BS_TYPE = '"..distribution_info.bs_type.."' AND S_BS_NO = '"..distribution_info.bs_no.."'"
|
|
nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "Distribution_CNTR_Detail", strCondition, strSetSQL)
|
if (nRet ~= 0) then return 1, "设置【配盘明细】 数量失败!"..strRetInfo end
|
else
|
local cg_detail
|
nRet, cg_detail = m3.GetDataObject( strLuaDEID, "CG_Detail", distribution_info.cg_detail_id )
|
if ( nRet ~= 0 ) then return 1, '获取【容器货品明细】对象失败!'..cg_detail end
|
|
distribution_detail = m3.AllocObject(strLuaDEID, "Distribution_CNTR_Detail")
|
distribution_detail.dc_no = dc_no
|
distribution_detail.cntr_code = cg_detail.cntr_code
|
distribution_detail.item_code = cg_detail.item_code
|
distribution_detail.item_name = cg_detail.item_name
|
distribution_detail.item_spec = cg_detail.item_spec
|
distribution_detail.cell_no = cg_detail.cell_no
|
distribution_detail.item_state = cg_detail.item_state
|
distribution_detail.item_state_name = cg_detail.item_state_name
|
distribution_detail.batch_no = cg_detail.batch_no
|
distribution_detail.serial_no = cg_detail.serial_no
|
distribution_detail.end_user = cg_detail.end_user
|
distribution_detail.owner = cg_detail.owner
|
distribution_detail.supplier = cg_detail.supplier
|
distribution_detail.uom = cg_detail.uom
|
distribution_detail.qty = distribution_info.qty
|
|
distribution_detail.bs_type = distribution_info.bs_type
|
distribution_detail.bs_no = distribution_info.bs_no
|
distribution_detail.bs_row_no = distribution_info.bs_row_no
|
distribution_detail.cg_detail_id = distribution_info.cg_detail_id
|
|
distribution_detail.wh_code = loc.wh_code
|
distribution_detail.area_code = loc.area_code
|
|
nRet, distribution_detail = m3.CreateDataObj( strLuaDEID, distribution_detail )
|
if ( nRet ~= 0 ) then return 1, '创建【配盘明细】对象失败!'..distribution_detail end
|
end
|
|
-- 仓库/库区量表+分配量
|
local item = {}
|
-- 量表变化参数
|
item[1] = {
|
N_ROW_NO = 1,
|
S_ITEM_CODE = distribution_detail.item_code,
|
S_ITEM_NAME = distribution_detail.item_name,
|
F_QTY = distribution_info.qty
|
}
|
-- + 仓库/库区分配量
|
nRet, strRetInfo = wms.wms_IPA_Start( loc.wh_code, loc.area_code, lua.table2str(item) )
|
if ( nRet ~= 0 or strRetInfo == '') then return 1, 'wms_IPA_Start 失败!'..strRetInfo end
|
local success
|
local pre_alloc_storage
|
success, pre_alloc_storage = pcall( json.decode, strRetInfo)
|
if ( success == false ) then return 1, "wms_IPA_Start 返回非法的JSON格式!"..pre_alloc_storage end
|
local trans_id = pre_alloc_storage.trans_id -- +分配量 事务标识
|
-- 如果没有trans_id说明+分配量失败
|
if ( trans_id == nil or trans_id == '') then
|
return 1, "系统在增加仓库/库区分配量时失败! 可能是库存量不足!"
|
end
|
-- CG_Detail 加分配量
|
strCondition = "S_ID = '"..distribution_info.cg_detail_id.."'"
|
nRet, strRetInfo = mobox.incDataObjAccQty ( strLuaDEID, "CG_Detail", strCondition, "F_QTY", "F_ALLOC_QTY", distribution_info.qty )
|
if ( nRet ~= 0 or strRetInfo ~= '') then
|
wms.wms_IPA_Abort( trans_id )
|
return 1, '在增加【容器货品明细】中的分配量时失败!'..strRetInfo
|
end
|
-- 业务来源这里加累计配盘数量
|
if ( distribution_info.bs_type == "Shipping_Order") then
|
-- 发货单
|
strCondition = "S_SHIPPING_NO = '"..distribution_info.bs_no.."' AND N_ROW_NO = "..distribution_info.bs_row_no
|
nRet, strRetInfo = mobox.incDataObjAccQty ( strLuaDEID, "Shipping_Detail", strCondition, "F_QTY", "F_ACC_D_QTY", distribution_info.qty )
|
if ( nRet ~= 0 or strRetInfo ~= '' ) then
|
wms.wms_IPA_Abort( trans_id )
|
return 1, '在增加【发货单明细】中的累计配货数量时失败!'..strRetInfo
|
end
|
nRet, strRetInfo = wms_out.Shipping_Order_CheckState( strLuaDEID, distribution_info.bs_no )
|
if ( nRet ~= 0 ) then
|
wms.wms_IPA_Abort( trans_id )
|
return 1, strRetInfo
|
end
|
else
|
-- 出库单
|
end
|
|
wms.wms_IPA_Commit( trans_id )
|
return 0
|
end
|
|
--[[
|
根据输入的出库单编码获取 出库单明细列表,oo_no_set 是一个出库单编码数组,如["OO010","OO012"]
|
返回值: 1 -- nRet 0 正确 2 --outbound_detail_list 出库单明细列表 table
|
]]
|
function wms_out.Get_Outbound_Detail_list( strLuaDEID, oo_no_set )
|
local nRet, strRetInfo
|
local where, nCount, n
|
local outbound_detail_list = {}
|
|
nCount = #oo_no_set
|
if ( nCount == 0 ) then
|
return 1, "出库单编码不能为空!"
|
end
|
if ( nCount == 1 ) then
|
where = " S_OO_NO = '"..oo_no_set[1].."'"
|
else
|
where = " S_OO_NO IN ("
|
for n = 1, nCount do
|
where = where.."'"..oo_no_set[n].."',"
|
end
|
where = lua.trim_laster_char( where )..")"
|
end
|
|
local strOrder = "S_ITEM_CODE"
|
|
nRet, strRetInfo = mobox.queryDataObjAttr( strLuaDEID, "Outbound_Detail", where, strOrder )
|
if ( nRet ~= 0 ) then return 1, "获取【发货单明细】失败! "..strRetInfo end
|
-- 如果没有满足条件的出库单明细就直接返回
|
if ( strRetInfo == '' ) then return 0, outbound_detail_list end
|
|
local retObjs = json.decode( strRetInfo )
|
local outbound_detail
|
|
for n = 1, #retObjs do
|
nRet, outbound_detail = m3.ObjAttrStrToLuaObj( "Outbound_Detail", lua.table2str(retObjs[n].attrs) )
|
table.insert( outbound_detail_list, outbound_detail )
|
end
|
return 0, outbound_detail_list
|
end
|
|
--[[
|
把配盘明细中的货品 批分到每个出库单明细
|
输入参数: d_cntr_detail_list [配盘明细]
|
返回值: 1 -- nRet 0 正确 2 --outbound_detail_list 出库单明细列表 table
|
]]
|
function wms_out.Split_Distribution_CNTR_Detail( strLuaDEID, wave_no, wave_cls_id, d_cntr_detail_list, outbound_detail_list )
|
local nRet, strRetInfo
|
local n, m, nCount
|
local new_d_cntr_detail_list = {}
|
local qty
|
|
nCount = #outbound_detail_list
|
for n = 1, #d_cntr_detail_list do
|
qty = d_cntr_detail_list[n].qty
|
for m = 1, nCount do
|
if ( d_cntr_detail_list[n].item_code == outbound_detail_list[m].item_code and
|
outbound_detail_list[m].qty > outbound_detail_list[m].acc_d_qty ) then
|
local d_cntr_detail = {
|
item_code = d_cntr_detail_list[n].item_code,
|
item_name = d_cntr_detail_list[n].item_name,
|
cntr_code = d_cntr_detail_list[n].cntr_code,
|
batch_no = d_cntr_detail_list[n].batch_no,
|
cell_no = d_cntr_detail_list[n].cell_no,
|
station = d_cntr_detail_list[n].station,
|
|
serial_no = d_cntr_detail_list[n].serial_no,
|
item_spec = d_cntr_detail_list[n].item_spec,
|
end_user = d_cntr_detail_list[n].end_user,
|
owner = d_cntr_detail_list[n].owner,
|
uom = d_cntr_detail_list[n].uom,
|
|
volume = d_cntr_detail_list[n].volume,
|
weight = d_cntr_detail_list[n].weight,
|
|
wh_code = d_cntr_detail_list[n].wh_code,
|
area_code = d_cntr_detail_list[n].area_code,
|
loc_code = d_cntr_detail_list[n].loc_code,
|
|
cg_detail_id = d_cntr_detail_list[n].cg_detail_id,
|
pick_box_code = "",
|
qty = 0
|
}
|
-- need_qty 出库单明细 需要批分的货品数量
|
-- split_qty 计算出可批分出去的货品数量
|
need_qty = outbound_detail_list[m].qty - outbound_detail_list[m].acc_d_qty
|
if ( qty > need_qty ) then
|
split_qty = need_qty
|
else
|
split_qty = qty
|
end
|
outbound_detail_list[m].acc_d_qty = outbound_detail_list[m].acc_d_qty + split_qty
|
qty = qty - split_qty
|
|
d_cntr_detail.qty = split_qty
|
d_cntr_detail.bs_type = "Outbound_Order"
|
d_cntr_detail.bs_no = outbound_detail_list[m].oo_no
|
d_cntr_detail.bs_row_no = outbound_detail_list[m].row_no
|
d_cntr_detail.wave_no = wave_no
|
d_cntr_detail.wave_cls_id = wave_cls_id
|
|
table.insert( new_d_cntr_detail_list, d_cntr_detail )
|
|
if ( qty == 0 ) then break end
|
end
|
end
|
end
|
return new_d_cntr_detail_list
|
end
|
|
local function generate_cg_detial_match_sql( item )
|
local item_sql = "a.S_ITEM_CODE = '"..item.item_code.."'"
|
|
if (item.batch_no ~= nil and item.batch_no ~= '') then
|
item_sql = item_sql.." AND a.S_BATCH_NO = '"..item.batch_no.."'"
|
end
|
if (item.serial_no ~= nil and item.serial_no ~= '') then
|
item_sql = item_sql.." AND a.S_SERIAL_NO = '"..item.serial_no.."'"
|
end
|
if (item.supplier ~= nil and item.supplier ~= '') then
|
item_sql = item_sql.." AND a.S_SUPPLIER_NO = '"..item.supplier.."'"
|
end
|
if (item.owner ~= nil and item.owner ~= '') then
|
item_sql = item_sql.." AND a.S_OWNER = '"..item.owner.."'"
|
end
|
if (item.item_state ~= nil and type(item.item_state) == "number") then
|
item_sql = item_sql.." AND a.N_ITEM_STATE = "..item.item_state
|
end
|
if (item.end_user ~= nil and item.end_user ~= '') then
|
item_sql = item_sql.." AND a.S_END_USER = '"..item.end_user.."'"
|
end
|
if (item.erp_wh_code ~= nil and item.erp_wh_code ~= '') then
|
item_sql = item_sql.." AND a.S_ERP_WH_CODE = '"..item.erp_wh_code.."'"
|
end
|
if (item.ext_attr1 ~= nil and item.ext_attr1 ~= '') then
|
item_sql = item_sql.." AND a.S_EXT_ATTR1 = '"..item.ext_attr1.."'"
|
end
|
if (item.ext_attr2 ~= nil and item.ext_attr2 ~= '') then
|
item_sql = item_sql.." AND a.S_EXT_ATTR2 = '"..item.ext_attr2.."'"
|
end
|
if (item.ext_attr3 ~= nil and item.ext_attr3 ~= '') then
|
item_sql = item_sql.." AND a.S_EXT_ATTR3 = '"..item.ext_attr3.."'"
|
end
|
if (item.ext_attr4 ~= nil and item.ext_attr4 ~= '') then
|
item_sql = item_sql.." AND a.S_EXT_ATTR4 = '"..item.ext_attr4.."'"
|
end
|
if (item.ext_attr5 ~= nil and item.ext_attr5 ~= '') then
|
item_sql = item_sql.." AND a.S_EXT_ATTR5 = '"..item.ext_attr5.."'"
|
end
|
return item_sql
|
end
|
|
--[[ 起源:巨星料箱配货算法, 可作为标准配货算法
|
|
说明: 根据货品编码 item_code 确定货品,根据批次号顺序配盘,批次号小的优先出
|
输入参数:
|
item_list 需要出库的货品清单,其中item中参与查询条件的属性
|
{item_code, batch_no,serial_no,supplier,owner,item_state,end_user, erp_wh_code, ext_attr1,..ext_attr5}
|
parameter = {
|
wh_code, area_code 出库货品仓库-库区 ,
|
station -- 分拣站台, 可以为空
|
exit_loc -- 出库出口货位,货位对象{ area_code, code }
|
bs_type, bs_no 业务来源
|
order_by 匹配CG_Detail时的次序
|
}
|
match_method: 可以不输入默认为0,0表示会根据 item_list 中出现的 批次号,系列号等进行匹配, 1 -- 表示只对 item_code 进行匹配
|
返回:
|
d_cntr_list 配盘/Distribution_CNTR d_cntr_detail_list 配盘明细/Distribution_CNTR_Detail
|
|
更改记录:
|
V2.0 HAN 20241023
|
-- 取消查询时对容器锁的要求(不对容器锁进行查询)
|
-- 取消容器加锁(改成作业启动的时候加锁)
|
V3.0 HAN 20241027
|
加分件站台位置 station
|
V4.0 HAN 20241122
|
输入参数做了整合 把 wh_code, area_code, station, exit_loc, bs_type, bs_no 整合到 table 参数 parameter
|
{ wh_code, area_code, station, exit_loc, bs_type, bs_no, order_by }
|
其中 order_by 是CG_Detail表中的属性顺序
|
]]
|
function wms_out.Distribution_Procedure( strLuaDEID, item_list, parameter, d_cntr_list, d_cntr_detail_list, match_method )
|
local nRet, strRetInfo, strCondition
|
local n, nCount
|
local str_where = ''
|
local strOrder = ''
|
|
lua.Debug( strLuaDEID, debug.getinfo(1), "wms_out.Distribution_Procedure", parameter )
|
|
-- step1:输入参数判断,并且组织仓库查询条件
|
if ( parameter == nil or parameter == '') then return 1, "输入参数错误, wh_code必须有值" end
|
if ( parameter.wh_code == nil or parameter.wh_code == '' ) then
|
return 1, "输入参数错误, parameter.wh_code必须有值"
|
end
|
str_where = "S_WH_CODE = '"..parameter.wh_code.."'"
|
if ( parameter.area_code ~= nil and parameter.area_code ~= '') then
|
str_where = str_where.." AND S_AREA_CODE = '"..parameter.area_code.."'"
|
end
|
if ( parameter.exit_loc == nil or parameter.exit_loc == '' ) then
|
return 1, "输入参数错误, parameter.exit_loc 必须有值"
|
end
|
if ( match_method == nil or match_method == '' ) then match_method = 0 end
|
|
strTable = "TN_CG_Detail a LEFT JOIN TN_Container b ON a.S_CNTR_CODE = b.S_CODE" -- 联表
|
strAttrs = "a.S_CNTR_CODE, a.S_CELL_NO, a.S_BATCH_NO, a.F_QTY, a.F_ALLOC_QTY, a.S_ID, b.S_POSITION,"..
|
"a.S_SERIAL_NO, a.N_ITEM_STATE, a.S_END_USER, a.S_OWNER, a.S_SUPPLIER_NO,a.S_ERP_WH_CODE,"..
|
"a.S_EXT_ATTR1,a.S_EXT_ATTR2,a.S_EXT_ATTR3,a.S_EXT_ATTR4,a.S_EXT_ATTR5"
|
if ( parameter.order_by ~= nil and parameter.order_by ~= '') then
|
strOrder = "a."..parameter.order_by
|
end
|
local qty, alloc_qty, need_qty
|
local bFind
|
local item_condition, cg_detail_id, cell_no, cntr_loc_code
|
local batch_no, serial_no, item_state, end_user, owner, supplier, erp_wh_code
|
local ext_attr1, ext_attr2, ext_attr3, ext_attr4, ext_attr5
|
|
-- step2: 遍历待出库货品清单
|
for n = 1, #item_list do
|
-- step2.1 组织查询条件
|
-- CG_Detail中的货品物料编码一样,容器可以使用
|
-- V2.0 改进查询条件
|
if ( match_method == 1 ) then
|
item_condition = "a.S_ITEM_CODE = '"..item_list[n].item_code.."'"
|
else
|
item_condition = generate_cg_detial_match_sql( item_list[n] )
|
end
|
--strCondition = item_condition.." AND b.C_ENABLE = 'Y' AND b.N_LOCK_STATE = 0 AND a.F_QTY > a.F_ALLOC_QTY "..
|
-- "AND a.S_CNTR_CODE IN (select S_CNTR_CODE from TN_Loc_Container where S_LOC_CODE IN (select S_CODE from TN_Location where "..str_where..")) "
|
-- MDF BY WHB @20250110 在配盘时取消对容器锁的限制
|
strCondition = item_condition.." AND b.C_ENABLE = 'Y' AND a.F_QTY > a.F_ALLOC_QTY "..
|
"AND a.S_CNTR_CODE IN (select S_CNTR_CODE from TN_Loc_Container where S_LOC_CODE IN (select S_CODE from TN_Location where "..str_where..")) "
|
|
lua.Debug( strLuaDEID, debug.getinfo(1), "strCondition", strCondition )
|
|
-- step2.2 多表联查获取容器货品信息
|
nRet, strRetInfo = mobox.queryMultiTable(strLuaDEID, strAttrs, strTable, 1000, strCondition, strOrder )
|
|
if ( nRet ~= 0 ) then return 2, "查询【容器货品明细】信息失败! " .. strRetInfo end
|
if ( strRetInfo == '' ) then
|
lua.Debug( strLuaDEID, debug.getinfo(1), "查询条件 = ", strCondition )
|
return 1, "货品编码 = '"..item_list[n].item_code.."' 没找到库存! 错误编码:5001"
|
end
|
cg_detail_set = json.decode(strRetInfo)
|
-- step2.3 根据出库数量遍历2.2获取的容器货品信息进行数量批分
|
-- item_list[n].qty --> 需要出库的数量 item_list[n].alloc_qty --> 已经配货数量
|
for m = 1, #cg_detail_set do
|
-- step2.3.1 配盘数量已经到达出库数量
|
|
if ( lua.equation( item_list[n].qty, item_list[n].alloc_qty ) ) then break end
|
-- step2.3.2 获取容器货品记录里的一些基本属性
|
cntr_code = cg_detail_set[m][1]
|
cell_no = cg_detail_set[m][2]
|
batch_no = cg_detail_set[m][3]
|
-- 容器中货品数量
|
qty = lua.StrToNumber( cg_detail_set[m][4] )
|
-- 容器中已经被分配的数量
|
alloc_qty = lua.StrToNumber( cg_detail_set[m][5] )
|
cg_detail_id = cg_detail_set[m][6]
|
cntr_loc_code = cg_detail_set[m][7] -- 容器所在货位
|
--
|
serial_no = cg_detail_set[m][8]
|
item_state = lua.StrToNumber( cg_detail_set[m][9] )
|
end_user = cg_detail_set[m][10]
|
owner = cg_detail_set[m][11]
|
supplier = cg_detail_set[m][12]
|
erp_wh_code = cg_detail_set[m][13]
|
ext_attr1 = cg_detail_set[m][14]
|
ext_attr2 = cg_detail_set[m][15]
|
ext_attr3 = cg_detail_set[m][16]
|
ext_attr4 = cg_detail_set[m][17]
|
ext_attr5 = cg_detail_set[m][18]
|
|
-- 可用于配货的数量
|
qty = qty - alloc_qty
|
-- 还有多少货品没配
|
need_qty = item_list[n].qty - item_list[n].alloc_qty
|
|
-- 把容器加入 配货容器 清单
|
-- 初始化【配盘】容器信息
|
local distribution_cntr = {
|
cntr_code = cntr_code,
|
b_state = 1,
|
wh_code = parameter.wh_code,
|
area_code = parameter.area_code,
|
loc_code = cntr_loc_code,
|
bs_type = parameter.bs_type,
|
bs_no = parameter.bs_no,
|
exit_area_code = parameter.exit_loc.area_code,
|
exit_loc_code = parameter.exit_loc.code,
|
station = parameter.station,
|
dc_no = "" -- 配盘号
|
}
|
|
-- step2.3.3 检查一下容器是否已经在 d_cntr_list, 如果不存在要把 容器加入 d_cntr_list
|
bFind = false
|
for i = 1, #d_cntr_list do
|
if ( d_cntr_list[i].cntr_code == distribution_cntr.cntr_code ) then
|
bFind = true
|
break
|
end
|
end
|
if ( bFind == false ) then
|
table.insert( d_cntr_list, distribution_cntr )
|
end
|
|
-- step2.3.4 批分容器配盘数量
|
if ( need_qty > qty ) then
|
d_qty = qty
|
else
|
d_qty = need_qty
|
end
|
if ( d_qty == 0 ) then break end
|
item_list[n].alloc_qty = item_list[n].alloc_qty + d_qty
|
|
-- step2.3.5 生成 配盘明细并且加入配盘明细清单
|
local d_cntr_detail = {
|
cntr_code = cntr_code,
|
cell_no = cell_no,
|
batch_no = batch_no,
|
item_code = item_list[n].item_code,
|
item_name = item_list[n].item_name,
|
serial_no = serial_no, item_state = item_state, end_user = end_user, owner = owner, supplier = supplier, erp_wh_code = erp_wh_code,
|
ext_attr1 = ext_attr1, ext_attr2 = ext_attr2, ext_attr3 = ext_attr3, ext_attr4 = ext_attr4, ext_attr5 = ext_attr5,
|
|
volume = item_list[n].volume,
|
weight = item_list[n].weight,
|
bs_type = parameter.bs_type,
|
bs_no = parameter.bs_no,
|
bs_row_no = n, -- 货品清单中的顺序号
|
wave_cls_id = "",
|
wave_no = "",
|
qty = d_qty,
|
station = parameter.station,
|
cg_detail_id = cg_detail_id,
|
pick_box_code = "" -- 拣料箱编码
|
}
|
table.insert( d_cntr_detail_list, d_cntr_detail )
|
end
|
end
|
|
return 0
|
end
|
|
--[[
|
创建配盘及配盘明细数据对象
|
参数: d_cntr_list 【配盘】链表 [{cntr_code, bs_type, bs_no, wh_code, area_code, exit_area_code, exit_loc_code }]
|
d_cntr_detail_list【配盘明细】链表 [{item_code, item_name, batch_no, serial_no, cntr_code, cell_no, item_state, uom, qty, bs_type, bs_no, wave_cls_id, wave_no, cg_detail_id }]
|
返回值 nRet = 0 表示创建成功
|
]]
|
function wms_out.Creat_Distribution_list( strLuaDEID, d_cntr_list, d_cntr_detail_list )
|
local nRet, strRetInfo, n
|
|
local distribution_cntr
|
local nCount = #d_cntr_list
|
|
for n = 1, nCount do
|
distribution_cntr = m3.AllocObject(strLuaDEID, "Distribution_CNTR")
|
distribution_cntr.cntr_code = d_cntr_list[n].cntr_code
|
distribution_cntr.b_state = d_cntr_list[n].b_state
|
distribution_cntr.wh_code = d_cntr_list[n].wh_code
|
distribution_cntr.area_code = d_cntr_list[n].area_code
|
distribution_cntr.loc_code = d_cntr_list[n].loc_code
|
distribution_cntr.bs_type = d_cntr_list[n].bs_type
|
distribution_cntr.bs_no = d_cntr_list[n].bs_no
|
distribution_cntr.station = d_cntr_list[n].station
|
distribution_cntr.exit_area_code = d_cntr_list[n].exit_area_code
|
distribution_cntr.exit_loc_code = d_cntr_list[n].exit_loc_code
|
|
nRet, distribution_cntr = m3.CreateDataObj( strLuaDEID, distribution_cntr )
|
if ( nRet ~= 0 ) then return 1, '创建【配盘】对象失败!'..distribution_cntr end
|
d_cntr_list[n].dc_no = distribution_cntr.dc_no
|
end
|
|
local dc_no, wh_code, area_code, loc_code
|
local strCondition
|
local distribution_detail
|
|
-- step3 创建【配盘明细/Distribution_CNTR_Detail】
|
-- 获取 CG_Detail 信息
|
for m = 1, #d_cntr_detail_list do
|
|
-- 通过容器编码获取 配盘号
|
dc_no = ""
|
for n = 1, nCount do
|
if ( d_cntr_list[n].cntr_code == d_cntr_detail_list[m].cntr_code ) then
|
dc_no = d_cntr_list[n].dc_no
|
wh_code = d_cntr_list[n].wh_code
|
area_code = d_cntr_list[n].area_code
|
loc_code = d_cntr_list[n].loc_code
|
break
|
end
|
end
|
if ( dc_no == '' ) then
|
return 1, "容器'"..d_cntr_detail_list[m].cntr_code.."' 无法定位到【配盘】!"
|
end
|
|
distribution_detail = m3.AllocObject(strLuaDEID, "Distribution_CNTR_Detail")
|
distribution_detail.dc_no = dc_no
|
distribution_detail.cntr_code = d_cntr_detail_list[m].cntr_code
|
distribution_detail.item_code = lua.Get_StrAttrValue( d_cntr_detail_list[m].item_code )
|
distribution_detail.item_name = lua.Get_StrAttrValue( d_cntr_detail_list[m].item_name )
|
distribution_detail.item_spec = lua.Get_StrAttrValue( d_cntr_detail_list[m].item_spec )
|
distribution_detail.cell_no = lua.Get_StrAttrValue( d_cntr_detail_list[m].cell_no )
|
distribution_detail.item_state = lua.Get_NumAttrValue( d_cntr_detail_list[m].item_state )
|
distribution_detail.batch_no = lua.Get_StrAttrValue( d_cntr_detail_list[m].batch_no )
|
distribution_detail.serial_no = lua.Get_StrAttrValue( d_cntr_detail_list[m].serial_no )
|
distribution_detail.end_user = lua.Get_StrAttrValue( d_cntr_detail_list[m].end_user )
|
distribution_detail.owner = lua.Get_StrAttrValue( d_cntr_detail_list[m].owner )
|
distribution_detail.supplier = lua.Get_StrAttrValue( d_cntr_detail_list[m].supplier )
|
distribution_detail.erp_wh_code = lua.Get_StrAttrValue( d_cntr_detail_list[m].erp_wh_code )
|
|
distribution_detail.ext_attr1 = lua.Get_StrAttrValue( d_cntr_detail_list[m].ext_attr1 )
|
distribution_detail.ext_attr2 = lua.Get_StrAttrValue( d_cntr_detail_list[m].ext_attr2 )
|
distribution_detail.ext_attr3 = lua.Get_StrAttrValue( d_cntr_detail_list[m].ext_attr3 )
|
distribution_detail.ext_attr4 = lua.Get_StrAttrValue( d_cntr_detail_list[m].ext_attr4 )
|
distribution_detail.ext_attr5 = lua.Get_StrAttrValue( d_cntr_detail_list[m].ext_attr5 )
|
|
distribution_detail.uom = lua.Get_StrAttrValue( d_cntr_detail_list[m].uom )
|
distribution_detail.qty = lua.Get_NumAttrValue( d_cntr_detail_list[m].qty )
|
distribution_detail.bs_type = d_cntr_detail_list[m].bs_type
|
distribution_detail.bs_no = d_cntr_detail_list[m].bs_no
|
distribution_detail.bs_row_no = d_cntr_detail_list[m].bs_row_no
|
distribution_detail.cg_detail_id = d_cntr_detail_list[m].cg_detail_id
|
distribution_detail.wave_no = d_cntr_detail_list[m].wave_no
|
distribution_detail.wave_cls_id = d_cntr_detail_list[m].wave_cls_id
|
distribution_detail.wh_code = wh_code
|
distribution_detail.area_code = area_code
|
distribution_detail.loc_code = loc_code
|
distribution_detail.station = d_cntr_detail_list[m].station
|
distribution_detail.pick_box_code = d_cntr_detail_list[m].pick_box_code
|
nRet, distribution_detail = m3.CreateDataObj( strLuaDEID, distribution_detail )
|
|
if ( nRet ~= 0 ) then return 1, '创建【配盘明细】对象失败!'..distribution_detail end
|
|
end
|
return 0
|
end
|
|
|
-- 把出库单明细中的 item 加入出库明细汇总链表 sum_outbound_detail, 如果 货品编码相同 数量相加
|
-- strOONo 出库单号
|
-- sum_outbound_detail 出库单波次明细 [{item_name,item_code,qty,weight,volume,cell_type}]
|
-- 返回:nRet = 0 outbound_detail_info -- 出库单明细汇总信息
|
-- outbound_detail_info { total_qty, total_weight, total_volume }
|
function wms_out.Sum_outbound_detail( strLuaDEID, strOONo, sum_outbound_detail )
|
local nRet, strRetInfo
|
local strCondition
|
local data_objs
|
local outbound_detail_info = {
|
total_qty = 0, total_weight = 0, total_volume = 0
|
}
|
|
strCondition = "S_OO_NO = '"..strOONo.."'"
|
nRet, data_objs = m3.QueryDataObject(strLuaDEID, "Outbound_Detail", strCondition, "N_ROW_NO" )
|
if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objs end
|
if ( data_objs == '' ) then return 0, outbound_detail_info end
|
|
local n, item_code, qty, weight, volume
|
local detail_attrs
|
local bFind
|
|
for n = 1, #data_objs do
|
detail_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
|
item_code = lua.Get_StrAttrValue( detail_attrs.S_ITEM_CODE )
|
qty = lua.StrToNumber( detail_attrs.F_QTY )
|
weight = lua.StrToNumber( detail_attrs.F_WEIGHT )
|
volume = lua.StrToNumber( detail_attrs.F_VOLUME )
|
|
if ( item_code ~= '' and qty > 0 ) then
|
|
outbound_detail_info.total_qty = outbound_detail_info.total_qty + qty
|
outbound_detail_info.total_weight = outbound_detail_info.total_weight + qty*weight
|
outbound_detail_info.total_volume = outbound_detail_info.total_volume + qty*volume
|
|
bFind = false
|
for m = 1, #sum_outbound_detail do
|
if (sum_outbound_detail[m].item_code == item_code) then
|
bFind = true
|
sum_outbound_detail[m].qty = sum_outbound_detail[m].qty + qty
|
break
|
end
|
end
|
if ( bFind == false ) then
|
local out_item = {
|
item_code = item_code,
|
item_name = lua.Get_StrAttrValue( detail_attrs.S_ITEM_NAME ),
|
qty = qty,
|
alloc_qty = 0,
|
weight = weight,
|
volume = volume,
|
cell_type = lua.Get_StrAttrValue( detail_attrs.S_CELL_TYPE )
|
}
|
table.insert( sum_outbound_detail, out_item )
|
end
|
end
|
end
|
return 0, outbound_detail_info
|
end
|
|
|
--[[
|
分拣出库后,根据配盘明细中的分拣结果 影响 量表,CG_Detail
|
[配盘明细 /Distribution_CNTR_Detail] 的后处理程序
|
--减仓库/库区量表的分配量
|
--减仓库/库区量表的存储量
|
--生成【OnOff_Shelves】上下架记录
|
--减 CG_Detail 中的QTY个ALLOC_QTY
|
--更新 来源单号 中的累计出库数量
|
]]
|
function wms_out.Distribution_CNTR_Detail_PostProcess( strLuaDEID, wh_code, area_code, loc_code, dc_no )
|
local nRet, strRetInfo
|
|
if ( dc_no == nil or dc_no == '' ) then
|
return 1, "wms_out.Distribution_CNTR_Detail_PostProcess 函数中 dc_no 必须有值!"
|
end
|
|
local chg_target = '' -- 量表变化对象
|
if ( wh_code == '' or wh_code == nil ) then
|
return 1, "wms_out.Distribution_CNTR_Detail_PostProcess 函数中仓库编码必须有值!"
|
end
|
if ( area_code == nil ) then area_code = '' end
|
if ( loc_code == nil ) then loc_code = '' end
|
|
-- 获取 Organize_CNTR_Detail
|
local strOrder = ''
|
local strCondition = "S_DC_NO = '"..dc_no.."'"
|
|
nRet, strRetInfo = mobox.queryDataObjAttr( strLuaDEID, "Distribution_CNTR_Detail", strCondition, strOrder )
|
if ( nRet ~= 0 ) then return 1, "获取【配盘明细】失败! "..strRetInfo end
|
if ( strRetInfo == '' ) then
|
lua.Warning( strLuaDEID, debug.getinfo(1), "配盘号'"..dc_no.."'的明细为空!" )
|
return 1, "配盘号'"..dc_no.."'的明细为空!"
|
end
|
|
local retObjs = json.decode( strRetInfo )
|
local n
|
local inventory_change = {} -- 存储量变化
|
local alloc_qty_change = {} -- 分配量变化
|
local dc_detail = {}
|
local onoff_shelves = {} -- 上下架记录
|
local days = os.date("%Y%m%d")
|
local cancel_qty -- 取消数量
|
|
-- 获取存储量变化数据 并且创建 上下架记录
|
for n = 1, #retObjs do
|
nRet, dc_detail = m3.ObjAttrStrToLuaObj( "Distribution_CNTR_Detail", lua.table2str(retObjs[n].attrs) )
|
if ( nRet ~= 0 ) then return 1, "m3.ObjAttrStrToLuaObj(Organize_CNTR_Detail) 失败! "..dc_detail end
|
|
-- 强制完成产生的取消数量
|
cancel_qty = dc_detail.qty - dc_detail.acc_p_qty
|
if ( dc_detail.acc_p_qty > 0 ) then
|
-- 生成仓库量变化输入参数
|
local inventory_info = {
|
item_code = dc_detail.item_code,
|
item_name = dc_detail.item_name,
|
qty = dc_detail.acc_p_qty,
|
wh_code = wh_code,
|
area_code = area_code
|
}
|
table.insert( inventory_change, inventory_info )
|
|
-- 生成分配量变化输入参数
|
local alloc_qty_info = {
|
item_code = dc_detail.item_code,
|
item_name = dc_detail.item_name,
|
qty = dc_detail.qty,
|
wh_code = wh_code,
|
area_code = area_code
|
}
|
table.insert( alloc_qty_change, alloc_qty_info )
|
|
-- 生成上架记录【OnOff_Shelves】
|
onoff_shelves = m3.AllocObject(strLuaDEID,"OnOff_Shelves")
|
onoff_shelves.action = "-"
|
onoff_shelves.d_action = days
|
|
onoff_shelves.wh_code = wh_code
|
onoff_shelves.area_code = area_code
|
onoff_shelves.loc_code = loc_code
|
|
onoff_shelves.item_code = dc_detail.item_code
|
onoff_shelves.item_name = dc_detail.item_name
|
onoff_shelves.batch_no = dc_detail.batch_no
|
onoff_shelves.serial_no = dc_detail.serial_no
|
onoff_shelves.item_spec = dc_detail.item_spec
|
onoff_shelves.item_state_name = dc_detail.item_state_name
|
onoff_shelves.item_state = dc_detail.item_state
|
|
onoff_shelves.end_user = dc_detail.end_user
|
onoff_shelves.owner = dc_detail.owner
|
onoff_shelves.supplier = dc_detail.supplier
|
onoff_shelves.supplier_name = dc_detail.supplier_name
|
|
onoff_shelves.cntr_code = dc_detail.cntr_code
|
onoff_shelves.cell_no = dc_detail.cell_no
|
|
onoff_shelves.qty = dc_detail.acc_p_qty
|
onoff_shelves.uom = dc_detail.uom
|
|
onoff_shelves.bs_no = dc_detail.bs_no
|
onoff_shelves.bs_type = dc_detail.bs_type
|
|
nRet, onoff_shelves = m3.CreateDataObj( strLuaDEID, onoff_shelves )
|
if ( nRet ~= 0 ) then
|
return 1, 'mobox 创建【上下架记录】对象失败!'..onoff_shelves
|
end
|
|
-- 减 CG_Detail 中的QTY
|
if ( dc_detail.acc_p_qty > 0 ) then
|
nRet, strRetInfo = wms_cntr.Reduc_CG_Detail_Qty_AlloccQty( strLuaDEID, dc_detail.cg_detail_id, dc_detail.acc_p_qty, dc_detail.qty )
|
if ( nRet ~= 0 ) then return 1, "wms_cntr.Reduc_CG_Detail_Qty_AlloccQty 失败! "..strRetInfo end
|
end
|
end
|
-- 如果来源类型 = Outbound_Order 更新出库单的累计出库数量
|
if ( dc_detail.bs_type == "Outbound_Order" ) then
|
if ( dc_detail.bs_no ~= nil and dc_detail.bs_no ~= '' ) then
|
strCondition = "S_OO_NO = '"..dc_detail.bs_no.."' AND S_ITEM_CODE = '"..dc_detail.item_code.."'"
|
local strSetAttr = "F_ACC_O_QTY = F_ACC_O_QTY +"..dc_detail.acc_p_qty
|
if ( lua.equation( 0, cancel_qty ) == false ) then
|
strSetAttr = strSetAttr..", F_ACC_C_QTY = F_ACC_C_QTY + "..cancel_qty
|
end
|
nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "Outbound_Detail", strCondition, strSetAttr )
|
if (nRet ~= 0) then return 1, "设置【Outbound_Detail】累计出库数量失败!"..strRetInfo end
|
end
|
end
|
if ( dc_detail.wave_cls_id == 'Outbound_Wave' ) then
|
if ( dc_detail.wave_no ~= nil and dc_detail.wave_no ~= '' ) then
|
strCondition = "S_WAVE_NO = '"..dc_detail.wave_no.."' AND S_ITEM_CODE = '"..dc_detail.item_code.."'"
|
local strSetAttr = "F_ACC_O_QTY = F_ACC_O_QTY +"..dc_detail.acc_p_qty
|
if ( lua.equation( 0, cancel_qty ) == false ) then
|
strSetAttr = strSetAttr..", F_ACC_C_QTY = F_ACC_C_QTY + "..cancel_qty
|
end
|
nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "OW_Detail", strCondition, strSetAttr )
|
if (nRet ~= 0) then return 1, "设置【OW_Detail】累计出库数量失败!"..strRetInfo end
|
end
|
end
|
end
|
|
-- 存储量处理
|
if ( #inventory_change > 0 ) then
|
local str_inventory_change = lua.table2str( inventory_change )
|
if ( wh_code ~= '' and wh_code ~= nil ) then
|
-- 8 减仓库存储量
|
nRet, strRetInfo = wms.wms_AddWHInventoryChange(strLuaDEID, 8, str_inventory_change )
|
if ( nRet ~= 0 ) then return 1, "wms_AddWHInventoryChange 失败! "..strRetInfo end
|
end
|
|
if ( area_code ~= '' and area_code ~= nil ) then
|
-- 9 减库区存储量
|
nRet, strRetInfo = wms.wms_AddWHInventoryChange(strLuaDEID, 9, str_inventory_change )
|
if ( nRet ~= 0 ) then return 1, "wms_AddWHInventoryChange 失败! "..strRetInfo end
|
end
|
end
|
-- 分配量处理
|
if ( #alloc_qty_change > 0 ) then
|
local str_alloc_qty_change = lua.table2str( alloc_qty_change )
|
if ( wh_code ~= '' and wh_code ~= nil ) then
|
-- 10 减仓库分配量
|
nRet, strRetInfo = wms.wms_AddWHInventoryChange(strLuaDEID, 10, str_alloc_qty_change )
|
if ( nRet ~= 0 ) then return 1, "wms_AddWHInventoryChange 失败! "..strRetInfo end
|
end
|
|
if ( area_code ~= '' and area_code ~= nil ) then
|
-- 11 减库区分配量
|
nRet, strRetInfo = wms.wms_AddWHInventoryChange(strLuaDEID, 11, str_alloc_qty_change )
|
if ( nRet ~= 0 ) then return 1, "wms_AddWHInventoryChange 失败! "..strRetInfo end
|
end
|
end
|
return 0
|
end
|
|
local function create_so_cntr_detail( strLuaDEID, station, cntr_code, so_no, soc_no, item_code )
|
local nRet, strRetInfo
|
local obj_attrs, data_objs
|
local strCondition = "S_CNTR_CODE = '"..cntr_code.."'"
|
local so_cntr_detail
|
|
if ( item_code ~= nil and item_code ~= '' ) then
|
strCondition = strCondition.." AND S_ITEM_CODE = '"..item_code.."'"
|
end
|
|
nRet, data_objs = m3.QueryDataObject( strLuaDEID, "CG_Detail", strCondition )
|
if ( nRet ~= 0 ) then return 1, "获取【CG_Detail】失败! "..data_objs end
|
if ( data_objs == '' ) then return 0 end
|
|
for n = 1, #data_objs do
|
obj_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
|
|
so_cntr_detail = m3.AllocObject(strLuaDEID,"SO_CNTR_Detail")
|
so_cntr_detail.soc_no = soc_no
|
so_cntr_detail.station = station
|
so_cntr_detail.so_no = so_no
|
so_cntr_detail.cntr_code = cntr_code
|
so_cntr_detail.qty = lua.Get_NumAttrValue( obj_attrs.F_QTY )
|
so_cntr_detail.cell_no = obj_attrs.S_CELL_NO
|
so_cntr_detail.item_code = obj_attrs.S_ITEM_CODE
|
so_cntr_detail.item_name = obj_attrs.S_ITEM_NAME
|
so_cntr_detail.item_state = lua.StrToNumber( obj_attrs.N_ITEM_STATE )
|
so_cntr_detail.batch_no = obj_attrs.S_BATCH_NO
|
so_cntr_detail.serial_no = obj_attrs.S_SERIAL_NO
|
so_cntr_detail.erp_wh_code = obj_attrs.S_ERP_WH_CODE
|
so_cntr_detail.end_user = obj_attrs.S_END_USER
|
so_cntr_detail.owner = obj_attrs.S_OWNER
|
so_cntr_detail.supplier = obj_attrs.S_SUPPLIER_NO
|
|
so_cntr_detail.uom = obj_attrs.S_UOM
|
so_cntr_detail.ext_attr1 = obj_attrs.S_EXT_ATTR1
|
so_cntr_detail.ext_attr2 = obj_attrs.S_EXT_ATTR2
|
so_cntr_detail.ext_attr3 = obj_attrs.S_EXT_ATTR3
|
so_cntr_detail.ext_attr4 = obj_attrs.S_EXT_ATTR4
|
so_cntr_detail.ext_attr5 = obj_attrs.S_EXT_ATTR5
|
|
nRet, so_cntr_detail = m3.CreateDataObj( strLuaDEID, so_cntr_detail )
|
if ( nRet ~= 0 ) then
|
return 1, 'mobox 创建【指定出库容器货品明细】对象失败!'..so_cntr_detail
|
end
|
end
|
return 0
|
end
|
|
-- 根据指(so)定出库货品,创建指定出库容器和 指定出库容器明细
|
local function create_so_cntr_operation( strLuaDEID, station, so_no, cntr_code, to_loc, item_code, source_sys )
|
local nRet, strRetInfo
|
|
if ( source_sys == nil ) then source_sys = "" end
|
-- 获取容器所在的货位
|
local from_loc_code = wms_wh.GetLocCodeByCNTR( strLuaDEID, cntr_code )
|
if ( from_loc_code == '' ) then return 1, "容器'"..cntr_code.."'无法获取货位!" end
|
local from_loc
|
nRet, from_loc = wms_wh.GetLocInfo( from_loc_code )
|
if ( nRet ~= 0 ) then return 1, '获取货位信息失败! '..from_loc end
|
|
-- 创建 指定出库容器
|
local so_cntr = m3.AllocObject(strLuaDEID,"Specify_Outbound_CNTR")
|
|
so_cntr.so_no = so_no
|
so_cntr.cntr_code = cntr_code
|
so_cntr.wh_code = from_loc.wh_code
|
so_cntr.area_code = from_loc.area_code
|
so_cntr.loc_code = from_loc.code
|
so_cntr.to_loc_code = to_loc.code
|
so_cntr.station = station
|
nRet, so_cntr = m3.CreateDataObj( strLuaDEID, so_cntr )
|
if (nRet ~= 0) then return 1, "创建【盘点单】失败!"..so_cntr end
|
|
nRet, strRetInfo = create_so_cntr_detail( strLuaDEID, station, cntr_code, so_no, so_cntr.soc_no, item_code )
|
if ( nRet ~= 0 ) then return nRet, strRetInfo end
|
|
local operation = m3.AllocObject(strLuaDEID,"Operation")
|
operation.source_sys = source_sys
|
operation.start_wh_code = from_loc.wh_code
|
operation.start_area_code = from_loc.area_code
|
operation.start_loc_code = from_loc.code
|
|
operation.end_wh_code = to_loc.wh_code
|
operation.end_area_code = to_loc.area_code
|
operation.end_loc_code = to_loc.code
|
operation.lock_cntr = "N" -- 作业启动时不需要锁容器
|
operation.cntr_code = cntr_code
|
|
operation.op_type = wms_base.Get_nConst( strLuaDEID, "作业类型-出库" )
|
operation.op_def_name = "指定出库"
|
operation.bs_type = "Specify_Outbound"
|
operation.bs_no = so_no
|
nRet, operation = m3.CreateDataObj( strLuaDEID, operation )
|
if ( nRet ~= 0 ) then return 2, '创建【作业】失败!'..operation end
|
|
-- 容器加出库锁/2 -- 加内存同时加数据库
|
nRet, strRetInfo = wms_cntr.Lock( strLuaDEID, cntr_code, 2, so_no )
|
if ( nRet ~= 0 ) then
|
return 2, "给容器'"..cntr_code.."'加出库锁失败!"
|
end
|
|
return 0
|
end
|
|
--[[
|
根据容器号创建一个指定出库作业
|
SOO -- Specify Outbound Operation
|
输入参数:
|
so_no -- 指定出库指令号
|
cntr_code -- 容器编码
|
to_loc_code -- 出库口货位
|
op_def_name -- 作业类型
|
source_sys -- 来源系统
|
--]]
|
function wms_out.Create_SOO_ByContainer( strLuaDEID, station, so_no, cntr_code, to_loc_code, op_def_name, source_sys )
|
local nRet, strRetInfo, n
|
|
-- step1:输入参数合法性检查
|
if ( so_no == nil or so_no == '') then return 1, "so_no 必须有值!" end
|
if ( cntr_code == nil or cntr_code == '') then return 1, "cntr 必须有值!" end
|
if ( to_loc_code == nil or to_loc_code == '') then return 1, "loc_code 必须有值!" end
|
if ( station == nil or station == '') then return 1, "station 必须有值!" end
|
if ( source_sys == nil ) then source_sys = "" end
|
-- 判断目标货位是否正确
|
local to_loc
|
nRet, to_loc = wms_wh.GetLocInfo( to_loc_code )
|
if ( nRet ~= 0 ) then return 1, '获取货位信息失败! '..to_loc end
|
|
-- 创建指定出库容器+容器明细+作业
|
nRet, strRetInfo = create_so_cntr_operation( strLuaDEID, station, so_no, cntr_code, to_loc, "", source_sys )
|
if ( nRet ~= 0 ) then
|
wms.wms_AbortCntrLockTrans( so_no )
|
return nRet, strRetInfo
|
end
|
|
-- 设置 Specify_Outbound 状态为执行 N_B_STATE = 2 执行中
|
strUpdateSql = "N_B_STATE = 2, N_CNTR_TOTAL = 1"
|
strCondition = "S_SO_NO = '"..so_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Specify_Outbound", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then
|
wms.wms_AbortCntrLockTrans( so_no )
|
return 2, "更新【Specify_Outbound】信息失败!"..strRetInfo
|
end
|
-- create_so_cntr_operation 有锁容器操作
|
wms.wms_CommitCntrLockTrans( so_no )
|
|
|
return 0
|
end
|
|
--[[
|
根据物料/货品号创建指定出库作业(可能会有多个容器)
|
SOO -- Specify Outbound Operation
|
输入参数:
|
so_no -- 指定出库指令号
|
item_code -- 物料货品编码
|
to_loc_code -- 出库口货位
|
op_def_name -- 作业类型
|
source_sys -- 来源系统
|
--]]
|
function wms_out.Create_SOO_ByMaterial( strLuaDEID, station, so_no, area_code, item_code, to_loc_code, op_def_name, source_sys )
|
local nRet, strRetInfo, n
|
|
-- step1:输入参数合法性检查
|
if ( so_no == nil or so_no == '') then return 1, "so_no 必须有值!" end
|
if ( area_code == nil or area_code == '') then return 1, "area_code 必须有值!" end
|
if ( source_sys == nil ) then source_sys = "" end
|
if ( item_code == nil or item_code == '') then return 1, "item_code 必须有值!" end
|
if ( to_loc_code == nil or to_loc_code == '') then return 1, "loc_code 必须有值!" end
|
if ( station == nil or station == '') then return 1, "station 必须有值!" end
|
|
|
-- 判断目标货位是否正确
|
local to_loc
|
nRet, to_loc = wms_wh.GetLocInfo( to_loc_code )
|
if ( nRet ~= 0 ) then return 1, '获取货位信息失败! '..to_loc end
|
|
-- 通过货品找出货品所在容器
|
local str_good_condition
|
local success, queryInfo, dataSet
|
local nPage, nPageCount
|
local cntr_code
|
|
str_good_condition = "S_ITEM_CODE = '"..item_code.."' AND 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 S_AREA_CODE = '"..area_code.."'))"
|
|
-- 查询有该货品的容器编号
|
-- 获取货品所在容器(考虑到有比较极端情况容器数量大于1000因此采用 queryDataObjAttr2 )
|
nRet, strRetInfo = mobox.queryDataObjAttr2( strLuaDEID, "CG_Detail", str_good_condition, strOrder, 100, "S_CNTR_CODE" )
|
if ( nRet ~= 0 ) then return 1, "queryDataObjAttr2: "..strRetInfo end
|
if ( strRetInfo == '' ) then return 0 end
|
|
lua.Debug( strLuaDEID, debug.getinfo(1), "货品所在容器 -- >", strRetInfo )
|
|
success, queryInfo = pcall( json.decode, strRetInfo )
|
if ( success == false ) then return 2, "queryDataObjAttr2 返回结果啊非法的JSON格式!" end
|
|
queryID = queryInfo.queryID
|
nPageCount = queryInfo.pageCount
|
nPage = 1
|
dataSet = queryInfo.dataSet -- 查询出来的数据集
|
local count = 0
|
while (nPage <= nPageCount) do
|
for i = 1, #dataSet do
|
cntr_code = dataSet[i].attrs[1].value
|
nRet, strRetInfo = create_so_cntr_operation( strLuaDEID, station, so_no, cntr_code, to_loc, item_code, source_sys )
|
if ( nRet ~= 0 ) then
|
wms.wms_AbortCntrLockTrans( so_no )
|
return 1, "create_so_cntr_operation! ".. strRetInfo
|
end
|
count = count + 1
|
end
|
|
nPage = nPage + 1
|
if ( nPage <= nPageCount ) then
|
-- 取下一页
|
nRet, strRetInfo = mobox.queryDataObjAttr2( queryID, nPage)
|
if ( nRet ~= 0 ) then
|
wms.wms_AbortCntrLockTrans( so_no )
|
return 2, "queryDataObjAttr2失败! nPage="..nPage.." "..strRetInfo
|
end
|
queryInfo = json.decode(strRetInfo)
|
dataSet = queryInfo.dataSet
|
end
|
end
|
|
|
-- 设置 Specify_Outbound 状态为执行 N_B_STATE = 2 执行中
|
strUpdateSql = "N_B_STATE = 2, N_CNTR_TOTAL = "..count
|
strCondition = "S_SO_NO = '"..so_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Specify_Outbound", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then
|
wms.wms_AbortCntrLockTrans( so_no )
|
return 2, "更新【Specify_Outbound】信息失败!"..strRetInfo
|
end -- create_so_cntr_operation 有锁容器操作
|
wms.wms_CommitCntrLockTrans( so_no )
|
return 0
|
end
|
|
return wms_out
|