--[[
|
版本: Version 1.0
|
创建日期: 2025-1-27
|
创建人: HAN
|
|
功能:
|
和容器数据类(Container)相关的一些函数
|
|
-- CreateVirtual 创建一个虚拟容器
|
-- SetWeight 设置容器的重量
|
|
-- GetInfo 获取容器信息
|
-- InOperation 判断某个编号的容器是否被作业使用
|
-- Exist 判断某个编号的容器是否存在
|
-- Get_Loc_Container 获取货位中的容器编码
|
|
-- SetLock 容器加锁/解锁
|
-- Get_Container_Goods 获取容器货品明细
|
|
-- Reset 重新设置容器里和CG_Detail,Cell箱格相关的属性
|
|
-- CanUsedInOperation 检查容器是否可用于作业搬运
|
更改说明:
|
--]]
|
wms_inv = require ("wms_inventory")
|
|
local wms_cntr = {_version = "0.1.1"}
|
--[[
|
创建一个虚拟容器
|
--]]
|
function wms_cntr.CreateVirtual( strLuaDEID, container )
|
local nRet, strRetInfo, strErr
|
strErr = ''
|
|
-- 生成容器编码
|
local strCode = ''
|
local strHeader = 'VC'..os.date("%y%m")..'-'
|
nRet,strRetInfo = mobox.getSerialNumber( "虚拟容器", strHeader, 5 )
|
if ( nRet ~= 0 ) then
|
strErr = '申请虚拟容器编码失败!'..strRetInfo
|
return nRet, strErr
|
end
|
container.code = strRetInfo
|
|
-- 获取创建容器时需要的属性
|
nRet, container = m3.CreateDataObj( strLuaDEID, container )
|
if ( nRet ~= 0 ) then
|
return nRet, "CreateDataObj失败! "..container
|
end
|
|
return nRet, container
|
end
|
|
--[[
|
从 data_object 中获取混箱属性加到 Container_Ext
|
--]]
|
function wms_cntr.Add_CNTR_ExtInfo( strLuaDEID, cntr_code, mixing_attrs, data_object )
|
local cntr_ext_data = m3.AllocObject2( strLuaDEID, "Container_Ext" )
|
|
cntr_ext_data.S_CNTR_CODE = cntr_code
|
for _, mixing_attr in ipairs(mixing_attrs) do
|
cntr_ext_data[mixing_attr] = data_object[mixing_attr]
|
end
|
nRet, cntr_ext_data = m3.CreateDataObj2( strLuaDEID, cntr_ext_data, 1 ) -- 1 表示已经存在就覆盖
|
if ( nRet ~= 0 ) then
|
return 2, "创建[Container_Ext]失败!"..cntr_ext_data
|
end
|
return 0
|
end
|
|
--[[
|
设置容器的重量
|
参数:
|
cntr_code 容器编码
|
fWeight 容器重量
|
-- ]]
|
function wms_cntr.SetWeight( strLuaDEID, cntr_code, fWeight )
|
local nRet, strRetInfo, strErr
|
|
if ( cntr_code == nil or cntr_code == '' ) then return end
|
if ( fWeight == nil or fWeight < 0) then return end
|
|
local strSetAttr = "F_GOOD_WEIGHT = "..fWeight
|
local strCondition = "S_CNTR_CODE = '"..cntr_code .. "'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container", strCondition, strSetAttr )
|
if ( nRet ~= 0 ) then return nRet, strRetInfo end
|
return 0, "ok"
|
end
|
|
--[[
|
获取容器信息
|
参数:
|
cntr_code 容器编码
|
-- ]]
|
function wms_cntr.GetInfo( strLuaDEID, cntr_code )
|
if ( cntr_code == nil or cntr_code == '' ) then
|
return 1, "WMS_Container_GetBaseInfo 容器编号不能为空!"
|
end
|
|
local nRet, strRetInfo, id
|
local strCondition = "S_CODE = '"..cntr_code.."'"
|
nRet, id, strRetInfo = mobox.getDataObjAttrByKeyAttr( strLuaDEID, "Container", strCondition )
|
|
-- 返回1表示不存在
|
if ( nRet == 1 ) then return 0, "" end
|
|
if ( nRet ~= 0 ) then
|
return 2, "getDataObjAttrByKeyAttr 失败!"..id
|
end
|
|
if ( nRet ~= 0 ) then
|
return 2, "getDataObjAttrByKeyAttr 发生错误!"..id
|
end
|
local strJson
|
nRet, strJson = mobox.objAttrsToLuaJson( "Container", strRetInfo )
|
if ( nRet ~= 0 ) then
|
return 2, "objAttrsToLuaJson Container 失败!"..strRetInfo
|
end
|
|
local object, success
|
success, object = pcall( json.decode, strJson )
|
if ( success == false ) then
|
return 2,"objAttrsToLuaJson('Container') 返回的的JSON格式不合法!"
|
end
|
object.id = id
|
return 0, object
|
end
|
|
--[[
|
判断某个编号的容器是否被作业使用
|
参数:
|
cntr_code 容器编码
|
返回:
|
nRet
|
strRet -- yes -- 表示容器在作业中 no -- 表示没有
|
-- ]]
|
function wms_cntr.InOperation( strLuaDEID, cntr_code )
|
local strCondition
|
local nRet, strRetInfo
|
|
strCondition = "( N_B_STATE = 0 OR N_B_STATE = 1) AND S_CNTR_CODE = '"..cntr_code.."'"
|
nRet, strRetInfo = mobox.getDataObjCount( strLuaDEID, "Operation", strCondition )
|
if ( nRet ~= 0 ) then return nRet, strRetInfo end
|
local nCount = lua.StrToNumber( strRetInfo )
|
if ( nCount == 0 ) then return 0, "no" end
|
return 0, "yes"
|
end
|
|
--[[
|
判断某个编号的容器是否存在
|
参数:
|
cntr_code 容器编码
|
返回:
|
true 存在 false 不存在
|
-- ]]
|
function wms_cntr.Exist( strLuaDEID, cntr_code )
|
local nRet, strRetInfo
|
if ( cntr_code == nil or cntr_code == '' ) then
|
return false
|
end
|
local strCondition = "S_CODE = '"..cntr_code.."'"
|
nRet, strRetInfo = mobox.existThisData( strLuaDEID, "Container", strCondition )
|
if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), "existThisData 时失败! "..strRetInfo ) end
|
if ( strRetInfo == 'no' ) then return false end
|
return true
|
end
|
|
--[[
|
判断某个货位是否有绑定过容器
|
参数:
|
loc_code 货位编码
|
返回:
|
true 存在 false 不存在
|
-- ]]
|
function wms_cntr.Loc_Container_Exist( strLuaDEID, loc_code )
|
local nRet, strRetInfo
|
if ( cntr_code == nil or cntr_code == '' ) then
|
return false
|
end
|
local strCondition = "S_LOC_CODE = '"..loc_code.."'"
|
nRet, strRetInfo = mobox.existThisData( strLuaDEID, "Loc_Container", strCondition )
|
if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), "existThisData 时失败! "..strRetInfo ) end
|
if ( strRetInfo == 'no' ) then return false end
|
return true
|
end
|
|
--[[
|
获取货位中的容器编码
|
参数:
|
loc_code 货位编码
|
返回:
|
nRet 非0 失败
|
cntr_set: ["C1","C2"] 这是一个table对象
|
如果没有容器 返回空字符串
|
-- ]]
|
function wms_cntr.Get_Loc_Container( strLuaDEID, loc_code )
|
local nRet, strRetInfo
|
|
if ( loc_code == nil or loc_code == '' ) then
|
return 1, "wms_cntr.Get_Loc_Container 函数中loc_code不能为空!"
|
end
|
local strCondition = "S_LOC_CODE = '"..loc_code.."'"
|
local strOrder = "N_BIND_ORDER"
|
nRet, strRetInfo = mobox.queryDataObjAttr( strLuaDEID, "Loc_Container", strCondition, strOrder, "S_CNTR_CODE" )
|
if ( nRet ~= 0 ) then return 1, "获取【Loc_Container】失败! "..strRetInfo end
|
if ( strRetInfo == '' ) then return 0, "" end
|
|
local retObjs = json.decode( strRetInfo )
|
local n
|
local attrs
|
local cntr_set = {}
|
|
for n = 1, #retObjs do
|
attrs = retObjs[n].attrs
|
cntr_set[n] = attrs[1].value
|
end
|
|
return 0, cntr_set
|
end
|
|
--[[
|
获取容器所在货位
|
参数:
|
cntr_code 容器编码
|
返回:
|
nRet 非0 失败
|
str_loc_code 货位编码
|
-- ]]
|
function wms_cntr.Get_Container_Loc( strLuaDEID, cntr_code )
|
local nRet, strRetInfo
|
|
if ( cntr_code == nil or cntr_code == '' ) then
|
return 1, "wms_cntr.Get_Container_Loc 函数中 cntr_code 不能为空!"
|
end
|
local strCondition = "S_CNTR_CODE = '"..cntr_code.."'"
|
local strOrder = "N_BIND_ORDER"
|
nRet, strRetInfo = mobox.queryDataObjAttr( strLuaDEID, "Loc_Container", strCondition, strOrder, "S_LOC_CODE" )
|
if ( nRet ~= 0 ) then return 1, "获取【Loc_Container】失败! "..strRetInfo end
|
if ( strRetInfo == '' ) then return 0, "" end
|
|
local retObjs = json.decode( strRetInfo )
|
if ( #retObjs > 1 ) then
|
return 1, "容器'"..cntr_code.."'在多个货位,数据错误请及时处理!"
|
end
|
|
local attrs
|
attrs = retObjs[1].attrs
|
return 0, attrs[1].value
|
end
|
|
-- 更新 INV_Detail 会触发变更后事件
|
function wms_cntr.INV_Detail_Update( strLuaDEID, inv_detail_data )
|
if ( inv_detail.id == nil or inv_detail.id == '' ) then
|
return 1, "调用 wms_cntr.INV_Detail_Update 函数时参数不正确, ID不能为空!"
|
end
|
local nRet, strAttrs
|
nRet, strAttrs = mobox.objJsonToObjAttr(inv_detail.cls, lua.table2str(inv_detail))
|
if ( nRet ~= 0 ) then return nRet, strAttrs end
|
|
local strUpdate = '[{"id":"'..inv_detail.id..'","attrs":'..strAttrs..'}]'
|
local strRetInfo
|
|
nRet, strRetInfo = mobox.updateDataObj( strLuaDEID, inv_detail.cls, strUpdate, 1 )
|
if ( nRet ~= 0 ) then
|
return nRet, strRetInfo
|
end
|
return 0, "ok"
|
end
|
|
--[[
|
容器加解锁
|
cntr -- 容器对象/或容器编码
|
str_lock_state -- 锁状态名称
|
lock_op_no -- 加锁的业务编码
|
--]]
|
function wms_cntr.SetLock( strLuaDEID, cntr, str_lock_state, lock_op_no )
|
local nRet, strRetInfo
|
|
if ( str_lock_state == nil or str_lock_state == '') then
|
return 1, "wms_cntr.SetLock 函数中 str_lock_state 不能为空!"
|
end
|
-- 如果 cntr 是一个字符串那就是容器编码
|
if ( type(cntr) == "string" ) then
|
nRet, cntr = wms_cntr.GetInfo( strLuaDEID, cntr )
|
if ( nRet ~= 0 ) then return 1, "获取【容器】失败! " .. cntr end
|
else
|
if ( cntr == nil or cntr.cls ~= "Container" ) then
|
return 1, "wms_cntr.SetLock 函数中 cntr 不能为空,并且必须是容器对象"
|
end
|
end
|
if ( lock_op_no == nil ) then lock_op_no = '' end
|
|
local lock_state
|
if ( type(str_lock_state) == "string") then
|
lock_state = wms_base.Get_nConst( strLuaDEID, str_lock_state )
|
else
|
lock_state = str_lock_state
|
end
|
local str_lock_state = wms_base.GetDictItemName( strLuaDEID, "WMS_LocationLockState", lock_state )
|
|
if ( lock_state ~= 0 ) then
|
-- 如果已经有锁是不能继续加其它锁的
|
if (cntr.lock_state ~= 0) then
|
return 1, "容器'"..cntr.code.."'已经被业务'"..cntr.lock_op_code.."'锁定,不能继续加锁!"
|
end
|
end
|
|
-- 更新容器表Lock相关属性
|
local strCondition = "S_CODE = '"..cntr.code.."'"
|
local strSetAttr = "N_LOCK_STATE = "..lock_state..", S_LOCK_STATE = '"..str_lock_state.."', S_LOCK_OP_CODE ='"..lock_op_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container", strCondition, strSetAttr )
|
if ( nRet ~= 0 ) then lua.Error( strLuaDEID, debug.getinfo(1), "更新【容器】锁状态失败!"..strRetInfo ) end
|
return 0, ""
|
end
|
|
--[[
|
设置 Container_Cell 里的属性
|
ctd -- 容器类型定义
|
cell_list -- 当前容器中 Container_Cell 列表
|
cell_no -- 需要设置的料格编码
|
cntr_cell -- 料格属性
|
inv_detail_data 是比较全的 INV_Detail 中在本料格的属性,可以从中获取 match_attr 并且保存到 Container_Cell, 后面的 update 会用到
|
--]]
|
local function set_cell_list( ctd, cell_list, cell_no, cntr_cell, inv_detail_data )
|
local n, nRet
|
local volume = 0
|
local limit = 0
|
local weight = 0
|
local sku_count_method = inv_detail_data.S_COUNT_METHOD or ''
|
local cell_max_weight = 0
|
|
-- 获取料格计数的一些基本属性
|
if sku_count_method == "Limit" then
|
-- 如果料格是通过数量限制是否满格
|
local sku_grid_parm, success
|
if not lua.StrIsEmpty( inv_detail_data.S_SKU_GRID_PARM ) then
|
success, sku_grid_parm = pcall( json.decode, inv_detail_data.S_SKU_GRID_PARM )
|
if ( success == false ) then
|
return 1, "SKU 编码 = '"..inv_detail_data.S_ITEM_CODE.."' 的数据对象中 S_SKU_GRID_PARM 不符合json规范!"
|
end
|
nRet, limit = wms_base.Get_LoadingLimit( inv_detail_data.S_ITEM_CODE, sku_grid_parm, ctd.ctd_code, cntr_cell.cell_type )
|
if nRet ~= 0 then
|
return 1, limit
|
end
|
if limit <= 0 then
|
return 1, "SKU 编码 = '"..inv_detail_data.S_ITEM_CODE.."' 的数据对象中 S_SKU_GRID_PARM 不合规!"
|
end
|
elseif not lua.StrIsEmpty( inv_detail_data.N_LOADING_LIMIT ) then
|
limit = lua.Get_NumAttrValue( inv_detail_data.N_LOADING_LIMIT )
|
if limit <= 0 then
|
return 1, "SKU 编码 = '"..inv_detail_data.S_ITEM_CODE.."' 的数据对象中 N_LOADING_LIMIT 不合规!"
|
end
|
else
|
return 1, "SKU 编码 = '"..inv_detail_data.S_ITEM_CODE.."' 的数据对象中 S_SKU_GRID_PARM 为空!"
|
end
|
elseif sku_count_method == "Weight" then
|
-- 需要获取料格最大载重
|
local grid_def
|
nRet, grid_def = wms_cntr.Get_CTD_GridDef( ctd, cntr_cell.cell_type )
|
if nRet ~= 0 or grid_def.box_num <= 0 then
|
return 1, "容器类型'"..ctd.ctd_code.."'中没有定义 cell_type = '"..cntr_cell.cell_type.."'的定义"
|
end
|
cell_max_weight = ctd.load_capacity/grid_def.box_num
|
if cell_max_weight <= 0 then
|
return 1, "容器类型'"..ctd.ctd_code.."'中没容器载重定义不合规!"
|
end
|
|
weight = lua.Get_NumAttrValue( inv_detail_data.F_WEIGHT )
|
if weight <= 0 then
|
return 1, "SKU 编码 = '"..inv_detail_data.S_ITEM_CODE.."' 的数据对象中 F_WEIGHT 不合规!"
|
end
|
elseif sku_count_method == "Volume" or sku_count_method == "Mixed" then
|
volume = lua.Get_NumAttrValue( inv_detail_data.F_VOLUME )
|
if volume <= 0 then
|
return 1, "SKU 编码 = '"..inv_detail_data.S_ITEM_CODE.."' 的数据对象中 F_VOLUME 不合规!"
|
end
|
else
|
return 1, "SKU 编码 = '"..inv_detail_data.S_ITEM_CODE.."' 的数据对象中 S_COUNT_METHOD 为空或不合规!"
|
end
|
|
for n = 1, #cell_list do
|
if ( cell_list[n].cell_no == cell_no ) then
|
cell_list[n].good_volume = cntr_cell.good_volume
|
cell_list[n].good_weight = cntr_cell.good_weight
|
cell_list[n].qty = cntr_cell.qty
|
cell_list[n].item_code = cntr_cell.item_code
|
cell_list[n].item_name = cntr_cell.item_name
|
cell_list[n].item_state = cntr_cell.item_state
|
cell_list[n].storer = cntr_cell.storer
|
cell_list[n].wms_bn = cntr_cell.wms_bn
|
cell_list[n].cell_type = cntr_cell.cell_type
|
cell_list[n].item_cell_type = cntr_cell.item_cell_type
|
cell_list[n].inv_detail_data = inv_detail_data
|
if ( cell_list[n].item_cell_type < cell_list[n].cell_type ) then
|
cell_list[n].state = "Abnormal"
|
else
|
cell_list[n].state = "Normal"
|
end
|
|
-- 如果料格被强制设置为满
|
if ( cell_list[n].forced_fill == 'Y' ) then
|
cell_list[n].empty_full = 2
|
else
|
if sku_count_method == "Volume" or sku_count_method == "Mixed" then
|
if ( (cntr_cell.good_volume + volume) > cell_list[n].volume ) then
|
cell_list[n].empty_full = 2
|
else
|
cell_list[n].empty_full = 1
|
end
|
elseif sku_count_method == "Limit" then
|
if cntr_cell.qty >= limit then
|
cell_list[n].empty_full = 2
|
else
|
cell_list[n].empty_full = 1
|
end
|
elseif sku_count_method == "Weight" then
|
if ( (cntr_cell.good_weight + weight) > cell_max_weight ) then
|
cell_list[n].empty_full = 2
|
else
|
cell_list[n].empty_full = 1
|
end
|
end
|
end
|
return 0
|
end
|
end
|
return 1, "在 set_cell_list 时失败,无法匹配到料格列表!"
|
end
|
|
-- 更新 Container_Cell 里的属性
|
local function update_container_cell( strLuaDEID, ctd, cell_list )
|
local n, nRet, strRetInfo
|
local strCondition, strSetAttr
|
local si_match_attrs_count = #ctd.si_match_attrs
|
local match_attr_update = ''
|
local inv_detail_data = {}
|
local cntr_cell_data
|
|
for n = 1, #cell_list do
|
if ( cell_list[n].qty == 0 ) then
|
-- 空料格,属性全部设置为初始值
|
cntr_cell_data = m3.AllocObject2( strLuaDEID, "Container_Cell" )
|
cntr_cell_data.S_CNTR_CODE = cell_list[n].cntr_code
|
cntr_cell_data.S_CELL_NO = cell_list[n].cell_no
|
|
nRet, strSetAttr = mobox.objJsonToObjAttr( "Container_Cell", lua.table2str(cntr_cell_data))
|
if ( nRet ~= 0 ) then
|
return nRet, strSetAttr
|
end
|
nRet, strRetInfo = mobox.setDataObjAttr( strLuaDEID, "Container_Cell", cell_list[n].id, strSetAttr )
|
if ( nRet ~= 0 ) then
|
return 2, "setDataObjAttr 发生错误!"..strRetInfo
|
end
|
else
|
match_attr_update = ''
|
inv_detail_data = cell_list[n].inv_detail_data
|
-- 如果料格匹配还有附加的属性
|
if ( si_match_attrs_count > 0 ) then
|
for m = 1, si_match_attrs_count do
|
if ( lua.isTableEmpty(inv_detail_data) ) then
|
match_attr_update = match_attr_update..","..ctd.si_match_attrs[m].." = ''"
|
else
|
match_attr_update = match_attr_update..","..ctd.si_match_attrs[m].." = '"..inv_detail_data[ctd.si_match_attrs[m]].."'"
|
end
|
end
|
end
|
strCondition = " S_CELL_NO = '"..cell_list[n].cell_no.."' AND S_CNTR_CODE = '"..cell_list[n].cntr_code.."'"
|
strSetAttr = "F_GOOD_WEIGHT = "..cell_list[n].good_weight..", F_GOOD_VOLUME = "..cell_list[n].good_volume..", N_EMPTY_FULL = "..cell_list[n].empty_full..
|
", S_ITEM_CODE = '"..cell_list[n].item_code.."', S_ITEM_NAME = '"..cell_list[n].item_name.."', F_QTY = "..cell_list[n].qty..
|
", S_WMS_BN = '"..cell_list[n].wms_bn.."', S_ALLOC_OP_CODE = '', S_CELL_TYPE = '"..cell_list[n].cell_type.."'"..
|
", S_ITEM_CELL_TYPE = '"..cell_list[n].item_cell_type.."', S_STATE = '"..cell_list[n].state.."'"..
|
", S_ITEM_STATE = '"..cell_list[n].item_state.."', S_STORER = '"..cell_list[n].storer.."'"..match_attr_update
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container_Cell", strCondition, strSetAttr )
|
if ( nRet ~= 0 ) then
|
return 2, "更新【容器料格】信息失败!"..strRetInfo
|
end
|
end
|
end
|
|
return 0
|
end
|
|
-- 获取料箱空料格数量
|
local function get_empty_cell_num( cell_list )
|
local n, num
|
|
num = 0
|
for n = 1, #cell_list do
|
if ( cell_list[n].empty_full == 0 ) then
|
num = num + 1
|
end
|
end
|
return num
|
end
|
|
-- 根据料格里的空满状态判断容器是否可以设置为满状态
|
local function cntr_is_full( cell_list )
|
local n, nCount, full_cell_count
|
|
nCount = #cell_list
|
full_cell_count = 0
|
for n = 1, nCount do
|
if ( cell_list[n].forced_fill == 'Y' or cell_list[n].empty_full == 2 ) then
|
full_cell_count = full_cell_count + 1
|
end
|
end
|
if ( full_cell_count == nCount ) then return true end
|
return false
|
end
|
|
-- 根据INV_Detail中的信息信息盘点料格和料箱的空满,货物数量,总体积,重量等全部重新计算一次(巨星料箱库项目首次)
|
-- 在入库前调用一下这个函数确保【容器】【容器料格】的数据准确
|
-- cntr 是一个容器对象 ctd -- 容器类型定义
|
local function cntr_reset_by_inv_detail( strLuaDEID, ctd, cntr )
|
local strCondition, nRet
|
local data_objs
|
local nRet, strRetInfo
|
|
strCondition = "S_CNTR_CODE = '"..cntr.code.."'"
|
local strOrder = ""
|
local cntr_loc_pos = ""
|
|
nRet, strRetInfo = mobox.queryOneDataObjAttr(strLuaDEID, "Loc_Container", strCondition, strOrder, "S_LOC_CODE" )
|
if (nRet ~= 0) then return 2, "获取【货位容器绑定】信息失败! " .. strRetInfo end
|
if ( strRetInfo ~= "") then
|
local ret_info = json.decode(strRetInfo)
|
cntr_loc_pos = ret_info.attrs[1].value
|
end
|
|
-- type = 3 是料格容器
|
if ( cntr.type == "Cell_Box" ) then
|
strCondition = "S_CNTR_CODE = '"..cntr.code.."'"
|
nRet, data_objs = m3.QueryDataObject(strLuaDEID, "Container_Cell", strCondition, "S_CELL_NO" )
|
if (nRet ~= 0) then return 2, "QueryDataObject失败!"..data_objs end
|
if ( data_objs == '' ) then return 0 end
|
|
local n, nCount, nCellCount
|
local cell_attrs
|
|
nCellCount = #data_objs
|
if ( 0 == nCellCount ) then return 0 end
|
|
local cell_list = {}
|
local attrs = {}
|
|
for n = 1, nCellCount do
|
obj_attrs = m3.KeyValueAttrsToObjAttr(data_objs[n].attrs)
|
local cell = {
|
id = data_objs[n].id,
|
--attrs = obj_attrs,
|
cntr_code = obj_attrs.S_CNTR_CODE,
|
cell_no = obj_attrs.S_CELL_NO,
|
cell_type = cntr.spec,
|
item_code = '',
|
item_name = '',
|
item_state = '',
|
storer = '',
|
item_cell_type = '',
|
state = 'Normal',
|
wms_bn = '',
|
qty = 0,
|
forced_fill = obj_attrs.C_FORCED_FILL,
|
volume = lua.StrToNumber( obj_attrs.F_VOLUME ), -- 料格体积
|
good_volume = 0,
|
good_weight = 0,
|
empty_full = 0,
|
inv_detail_data = {}
|
}
|
table.insert( cell_list, cell )
|
end
|
|
-- 获取CG_Detial + SKU 中的属性
|
local strTable = "TN_INV_Detail a LEFT JOIN TN_SKU b ON ( a.S_ITEM_CODE = b.S_ITEM_CODE and a.S_STORER = b.S_STORER )"
|
-- 要查询的属性
|
local strAttrs = ""
|
local m
|
local INV_DETAIL_BASE_ATTRS_COUNT = #INV_DETAIL_BASE_ATTRS
|
local attr_set = {}
|
for m = 1, INV_DETAIL_BASE_ATTRS_COUNT do
|
strAttrs = strAttrs.."a."..INV_DETAIL_BASE_ATTRS[m]..","
|
table.insert( attr_set, INV_DETAIL_BASE_ATTRS[m] )
|
end
|
local UDF_ATTRS_COUNT = #UDF_ATTRS
|
for m = 1, UDF_ATTRS_COUNT do
|
strAttrs = strAttrs.."a."..UDF_ATTRS[m]..","
|
table.insert( attr_set, UDF_ATTRS[m] )
|
end
|
strAttrs = strAttrs.."b.F_VOLUME, b.F_WEIGHT, b.S_CELL_TYPE, b.S_SKU_GRID_PARM, b.S_COUNT_METHOD, b.N_LOADING_LIMIT"
|
table.insert( attr_set, "F_VOLUME" )
|
table.insert( attr_set, "F_WEIGHT" )
|
table.insert( attr_set, "S_CELL_TYPE" )
|
table.insert( attr_set, "S_SKU_GRID_PARM" )
|
table.insert( attr_set, "S_COUNT_METHOD" )
|
table.insert( attr_set, "N_LOADING_LIMIT" )
|
|
-- 入库批次也要进行排序
|
strOrder = "a.S_CELL_NO, a.S_WMS_BN"
|
strCondition = "a.S_CNTR_CODE = '"..cntr.code.."'"
|
nRet, strRetInfo = mobox.queryMultiTable(strLuaDEID, strAttrs, strTable, 2000, strCondition, strOrder )
|
if ( nRet ~= 0 ) then return 2, "queryMultiTable 失败!"..strRetInfo end
|
|
local n, qty
|
local ret_data = {}
|
if ( strRetInfo ~= '' ) then
|
ret_data = json.decode(strRetInfo)
|
nCount = #ret_data
|
else
|
nCount = 0
|
end
|
|
local cell_no, item_cell_type
|
local current_cell_no = ''
|
local sum_volume, sum_weight, sum_qty
|
local volume, weight, qty
|
local item_code, item_name, wms_bn
|
local cg_detail_count = nCount
|
local good_weigth, good_volume, good_num
|
local cell_type = cntr.spec
|
|
-- 计算料箱料格的体积、重量,已经料箱格的空满状态
|
-- 料格里的货品重量、体积
|
sum_volume = 0
|
sum_weight = 0
|
sum_qty = 0
|
-- 整个料箱里的货品重量、体积
|
good_weigth = 0
|
good_volume = 0
|
good_num = 0
|
|
local cntr_cell = {}
|
local inv_detail_data = {}
|
local data_obj
|
local mixing_rule_value = {} -- 混箱属性值 {S_BATCH_NO = 'x'}
|
|
if ( nCount > 0 ) then
|
for n = 1, nCount do
|
nRet, data_obj = lua.GetDataAttrObj_By_StrArray( attr_set, ret_data[n] )
|
if ( nRet ~= 0 ) then
|
return 1, data_obj
|
end
|
cell_no = lua.Get_StrAttrValue( data_obj.S_CELL_NO )
|
if ( current_cell_no == '' ) then
|
current_cell_no = cell_no
|
end
|
if ( current_cell_no ~= cell_no ) then
|
cntr_cell.qty = sum_qty
|
cntr_cell.good_volume = sum_volume
|
cntr_cell.good_weight = sum_weight
|
|
nRet, strRetInfo = set_cell_list( ctd, cell_list, current_cell_no, cntr_cell, inv_detail_data )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
|
sum_volume = 0
|
sum_weight = 0
|
sum_qty = 0
|
current_cell_no = cell_no
|
end
|
|
if ctd.have_mixing_rule then
|
-- 获取混箱属性
|
for _, mixing_attr in ipairs(ctd.mixing_attrs) do
|
mixing_rule_value[mixing_attr] = data_obj[mixing_attr]
|
end
|
end
|
|
cntr_cell.cell_type = cell_type
|
cntr_cell.item_code = lua.Get_StrAttrValue( data_obj.S_ITEM_CODE )
|
cntr_cell.item_name = lua.Get_StrAttrValue( data_obj.S_ITEM_NAME )
|
cntr_cell.item_state = lua.Get_StrAttrValue( data_obj.S_ITEM_STATE )
|
cntr_cell.storer = lua.Get_StrAttrValue( data_obj.S_STORER )
|
cntr_cell.wms_bn = lua.Get_StrAttrValue( data_obj.S_WMS_BN )
|
inv_detail_data = data_obj
|
|
qty = lua.Get_NumAttrValue( data_obj.F_QTY )
|
volume = lua.Get_NumAttrValue( data_obj.F_VOLUME )
|
weight = lua.Get_NumAttrValue( data_obj.F_WEIGHT)
|
cntr_cell.item_cell_type = lua.Get_StrAttrValue( data_obj.S_CELL_TYPE )
|
|
volume = volume*qty
|
weight = weight*qty
|
|
good_weigth = good_weigth + weight
|
good_volume = good_volume + volume
|
good_num = good_num + qty
|
|
sum_volume = sum_volume + volume
|
sum_weight = sum_weight + weight
|
sum_qty = sum_qty + qty
|
end
|
cntr_cell.qty = sum_qty
|
cntr_cell.good_volume = sum_volume
|
cntr_cell.good_weight = sum_weight
|
|
nRet, strRetInfo = set_cell_list( ctd, cell_list, current_cell_no, cntr_cell, inv_detail_data )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
-- 设置 容器扩展属性
|
if ctd.have_mixing_rule then
|
nRet, strRetInfo = wms_cntr.Add_CNTR_ExtInfo( strLuaDEID, cntr.code, ctd.mixing_attrs, mixing_rule_value )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
end
|
else
|
-- 空料箱,混箱属性也需要清空
|
if ctd.have_mixing_rule then
|
strCondition = "S_CNTR_CODE = '" .. cntr.code .."'"
|
nRet, strRetInfo = mobox.dbdeleteData(strLuaDEID, "Container_Ext", strCondition)
|
if (nRet ~= 0) then
|
return 1, "删除【Container_Ext】失败!"..strRetInfo
|
end
|
end
|
end
|
|
-- 更新【容器料格】属性
|
nRet, strRetInfo = update_container_cell( strLuaDEID, ctd, cell_list )
|
if ( nRet ~= 0 ) then
|
return 2, strRetInfo
|
end
|
|
-- 更新【容器】本身属性
|
local empty_cell_num = get_empty_cell_num( cell_list )
|
local strSetAttr
|
local empty_full = 0
|
|
-- V2.0 MDF BY WHB 对容器空满状态判断的改进
|
if ( cntr.forced_fill == 'Y' ) then
|
empty_full = 2
|
else
|
if ( empty_cell_num == cntr.max_cell_num ) then
|
empty_full = 0
|
else
|
empty_full = 1
|
if ( 0 == empty_cell_num ) then
|
-- 判断一下容器里的料格是否都是已经满,那么料箱也要设置为满
|
if ( cntr_is_full( cell_list ) ) then
|
empty_full = 2
|
end
|
end
|
end
|
end
|
if ( cntr.max_weight > 0 ) then
|
if ( ( good_weigth + cntr.weight ) >= cntr.max_weight ) then
|
empty_full = 2
|
end
|
end
|
|
strCondition = "S_CODE = '"..cntr.code.."'"
|
strSetAttr = "N_ALLOC_CELL_NUM = 0, N_EMPTY_CELL_NUM = "..empty_cell_num..", N_EMPTY_FULL = "..empty_full..", N_DETAIL_COUNT = "..cg_detail_count..
|
", F_GOOD_WEIGHT = "..good_weigth..", F_GOOD_VOLUME = "..good_volume..", N_GOOD_NUM = "..good_num..", S_POSITION = '"..cntr_loc_pos.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container", strCondition, strSetAttr )
|
if ( nRet ~= 0 ) then return 2, "更新【容器料格】信息失败!"..strRetInfo end
|
else
|
-- 重置一下 容器中的 N_DETAIL_COUNT 即可
|
strCondition = "S_CNTR_CODE = '"..cntr.code.."'"
|
nRet, strRetInfo = mobox.getDataObjCount( strLuaDEID, "INV_Detail", strCondition )
|
if ( nRet ~= 0 ) then
|
return 2, strRetInfo
|
end
|
nCount = lua.StrToNumber( strRetInfo )
|
strCondition = "S_CODE = '"..cntr.code.."'"
|
strSetAttr = "N_DETAIL_COUNT = "..nCount..", S_POSITION = '"..cntr_loc_pos.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container", strCondition, strSetAttr )
|
if ( nRet ~= 0 ) then
|
return 2, "更新【容器料格】信息失败!"..strRetInfo
|
end
|
if nCount == 0 then
|
-- 空料箱,混箱属性也需要清空
|
if ctd.have_mixing_rule then
|
strCondition = "S_CNTR_CODE = '" .. cntr.code .."'"
|
nRet, strRetInfo = mobox.dbdeleteData(strLuaDEID, "Container_Ext", strCondition)
|
if (nRet ~= 0) then
|
return 1, "删除【Container_Ext】失败!"..strRetInfo
|
end
|
end
|
else
|
strCondition = "S_CNTR_CODE = '"..cntr.code.."'"
|
nRet, data_obj = m3.GetDataObjByCondition2( strLuaDEID, "INV_Detail", strCondition, "T_CREATE" )
|
if ( nRet == 0 ) then
|
nRet, strRetInfo = wms_cntr.Add_CNTR_ExtInfo( strLuaDEID, cntr.code, ctd.mixing_attrs, data_obj )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
end
|
end
|
end
|
|
return 0
|
end
|
|
function wms_cntr.Reset( strLuaDEID, cntr )
|
local strCondition, nRet, strRetInfo
|
|
if ( cntr == nil ) then
|
return 1, "Rest函数中cntr必须有值!"
|
end
|
local ctd -- 容器类型定义
|
nRet, ctd = wms_cntr.GetCTDInfo( cntr.ctd_code )
|
if ( nRet ~= 0 ) then
|
return 2, ctd
|
end
|
|
-- 重置容器属性
|
nRet, strRetInfo = cntr_reset_by_inv_detail( strLuaDEID, ctd, cntr )
|
if ( nRet ~= 0 ) then
|
return 2, strRetInfo
|
end
|
return 0
|
end
|
|
function wms_cntr.Lock( strLuaDEID, cntr_code, lock_state, op_code )
|
local nRet, strRetInfo
|
|
nRet, strRetInfo = wms.wms_LockCntr( cntr_code, 2, op_code )
|
if ( nRet ~= 0 ) then
|
return 1, "给容器'"..cntr_code.."'加出库锁失败!"
|
end
|
|
local strCondition = "S_CODE = '"..cntr_code.."'"
|
local strSetAttr = "N_LOCK_STATE = "..lock_state..", S_LOCK_OP_CODE = '"..op_code.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition(strLuaDEID, "Container", strCondition, strSetAttr )
|
if (nRet ~= 0) then return 2, "设置【Container】状态失败!"..strRetInfo end
|
|
return 0
|
end
|
|
-- 容器中的 N_ALLOC_CELL_NUM + 1, 料格 N_EMPTY_FULL = 3 (预分配)
|
-- bs_no 产生预分配料格的业务编码
|
-- 预分配一个容器料格
|
function wms_cntr.CNTR_cell_alloc_set( strLuaDEID, cntr_code, cell_no, bs_no )
|
local nRet, strRetInfo
|
local strCondition = "S_CODE = '"..cntr_code.."'"
|
local strUpdateSql = "N_ALLOC_CELL_NUM = N_ALLOC_CELL_NUM + 1"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then return 1, strRetInfo end
|
|
strCondition = "S_CELL_NO = '"..cell_no.."' AND S_CNTR_CODE = '"..cntr_code.."'"
|
strUpdateSql = "N_EMPTY_FULL = 3, S_ALLOC_OP_CODE = '"..bs_no.."'"
|
nRet, strRetInfo = mobox.updateDataAttrByCondition( strLuaDEID, "Container_Cell", strCondition, strUpdateSql )
|
if ( nRet ~= 0 ) then
|
return 1, strRetInfo
|
end
|
return 0
|
end
|
|
--[[
|
检查容器是否可以用于作业中,如果容器在一个非完成的作业中,不能进行用这个容器创建作业
|
返回值:
|
nRet, can_usedinop
|
--]]
|
function wms_cntr.CanUsedInOperation( strLuaDEID, cntr_code )
|
local nRet, strRetInfo
|
|
if ( cntr_code == '' or cntr_code == nil ) then
|
return 1, "CanUsedInOperation 函数中参数 cntr_code 必须有值!"
|
end
|
|
local strCondition = "N_B_STATE IN ( 0,1,3,4,5,6 ) AND S_CNTR_CODE = '"..cntr_code.."'"
|
nRet, strRetInfo = mobox.existThisData( strLuaDEID, "Operation", strCondition )
|
if ( nRet ~= 0 ) then return 2, strRetInfo end
|
if ( strRetInfo == "yes" ) then
|
-- 检测容器已经存在没完成的作业
|
return 0, false
|
end
|
return 0, true
|
end
|
|
-- 容器定义相关 ---
|
--[[
|
检查混箱,匹配等属性是否正确,并且返回这些属性的类型值
|
输入参数: str_attrs -- S_BATCH_NO,S_UDF01,... 属性字符串
|
返回: nRet, attrs, attrs_def_list
|
attrs -- {"S_BATCH_NO","S_UDF01",...}
|
attrs_def_list = { { attr = "S_ITEM_CODE", type = "string/number"},...}
|
--]]
|
local function check_attrs( str_attrs )
|
local nRet, strRetInfo
|
local attr_type
|
local attrs_def_list = {}
|
local attrs = {}
|
local attr_type_def = {}
|
|
if str_attrs == nil or str_attrs == '' then
|
return 0, {}
|
end
|
local seg = lua.split( str_attrs, ";" )
|
for i = 1, #seg do
|
table.insert( attrs, seg[i] )
|
end
|
-- 获取匹配属性的类型(数据类为 INV_Detail)
|
|
nRet, strRetInfo = mobox.getClassAttrType( "INV_Detail", lua.table2str( attrs ) )
|
if nRet ~= 0 then
|
return 1, strRetInfo
|
end
|
attr_type_def = json.decode( strRetInfo )
|
|
-- 上面的这个函数不正确,用下面的暂时替换一下
|
for _, attr in ipairs( attrs ) do
|
attr_type_def[attr] = "char"
|
end
|
|
local val
|
for _, attr in ipairs( attrs ) do
|
attr_type = attr_type_def[attr] or ''
|
val = ''
|
if attr_type == '' then
|
return 1, "属性'"..attr.."'不是 INV_Detial 中定义的属性!"
|
elseif attr_type == 'int' or attr_type == 'float' or attr_type == 'bigint' or attr_type == 'dict-int' or attr_type == 'computed' then
|
val = 'number'
|
else
|
val = 'string'
|
end
|
local attr_type = {
|
attr = attr, type = val
|
}
|
table.insert( attrs_def_list, attr_type )
|
end
|
return 0, attrs, attrs_def_list
|
end
|
|
local function grid_box_num_sort( a, b )
|
return a.box_num < b.box_num
|
end
|
--[[
|
获取容器类型定义数据对象
|
有些数据需要进一步细化,比如匹配规则中的属性的类型
|
-- ]]
|
function wms_cntr.GetCTDInfo( ctd_code )
|
local nRet, strRetInfo
|
|
if ( ctd_code == nil or ctd_code == '' ) then
|
return 1, "GetCTDInfo 函数中 cntr_code 不能为空!"
|
end
|
local ctd_data
|
nRet, ctd_data = m3.GetDataFromCache( "Container_Type_Def", ctd_code )
|
if ( nRet ~= 0 ) then
|
return 2, ctd_data
|
end
|
|
nRet, strRetInfo = mobox.objJsonToLuaJson( "Container_Type_Def", lua.table2str(ctd_data) )
|
if ( nRet ~= 0 ) then
|
return 1, strRetInfo
|
end
|
local ctd, success
|
success, ctd = pcall( json.decode, strRetInfo )
|
if ( success == false ) then
|
return 1,"objAttrsToLuaJson('Container') 返回的的JSON格式不合法! --> "..strRetInfo
|
end
|
|
-- 混箱规则,如果 mixing_attrs_def 有值满足这些要求的SKU才能放一个料箱
|
local str_val = ctd_data.S_MIXING_RULE or ''
|
ctd.mixing_attrs_def = {}
|
ctd.mixing_attrs = {}
|
ctd.have_mixing_rule = false
|
if ( str_val ~= '' ) then
|
nRet, ctd.mixing_attrs, ctd.mixing_attrs_def = check_attrs( str_val )
|
if nRet ~= 0 then
|
return 1, ctd.mixing_attrs
|
end
|
if #ctd.mixing_attrs_def > 0 then
|
ctd.have_mixing_rule = true
|
end
|
end
|
|
-- 料格里符合下面条件的SKU可以加入这个料格
|
ctd.si_enable = ctd.si_enable == 'Y' and true or false
|
ctd.si_match_attrs_def = {}
|
ctd.si_match_attrs = {}
|
local str_val = ctd_data.S_SI_MATCH_ATTRS or ''
|
if ( str_val ~= '' ) then
|
nRet, ctd.si_match_attrs, ctd.si_match_attrs_def = check_attrs( str_val )
|
if nRet ~= 0 then
|
return 1, ctd.si_match_attrs
|
end
|
end
|
|
-- 料格里符合下面条件的SKU数量可以相加
|
ctd.qty_merge = ctd.qty_merge == 'Y' and true or false
|
ctd.merge_attrs_def = {}
|
ctd.merge_attrs = {}
|
str_val = ctd_data.S_MERGE_ATTRS or ''
|
if ( str_val ~= '' ) then
|
nRet, ctd.merge_attrs, ctd.merge_attrs_def = check_attrs( str_val )
|
if nRet ~= 0 then
|
return 1, ctd.merge_attrs
|
end
|
end
|
|
ctd.check_capacity = ctd.check_capacity == 'Y' and true or false
|
str_val = ctd_data.S_GRID_BOX_DEF or ''
|
if ( str_val ~= '' ) then
|
local success
|
success, ctd.grid_box_def = pcall( json.decode, str_val )
|
if ( success == false ) then
|
return 1, "容器类型定义'"..ctd.ctd_code.."'中的料格定义不合规!"
|
end
|
-- 检查输入的 box_num 不能为 <=0
|
for _, box_def in ipairs( ctd.grid_box_def ) do
|
if box_def.box_num <= 0 then
|
return 1, "容器类型定义'"..ctd.ctd_code.."'中的料格定义不合规! box_num 必须大于0"
|
end
|
box_def.is_smallest = false -- 是这种类型料箱中最小的料格
|
end
|
-- grid_box_def 根据料格数量进行排序
|
table.sort( ctd.grid_box_def, grid_box_num_sort )
|
ctd.grid_box_def[#ctd.grid_box_def].is_smallest = true
|
else
|
ctd.grid_box_def = {}
|
end
|
return 0, ctd
|
end
|
|
-- 根据 cell_type 获取 grid 定义
|
function wms_cntr.Get_CTD_GridDef( ctd, cell_type )
|
if ctd == nil or cell_type == nil then
|
return 1, "wms_cntr.Get_CTD_GridDef 函数输入参数不能为 nil"
|
end
|
for _, box_def_item in ipairs( ctd.grid_box_def) do
|
if box_def_item.cell_type == cell_type then
|
return 0, box_def_item
|
end
|
end
|
return 1, "在容器类型定义中无法获取料格类型 = '"..cell_type.."' 的料格定义"
|
end
|
|
-- 根据 cell_type 获取下一个等级的料格 grid 定义
|
function wms_cntr.Get_CTD_Next_GridDef( ctd, cell_type )
|
if ctd == nil or cell_type == nil then
|
return 1, "wms_cntr.Get_CTD_Next_GridDef 函数输入参数不能为 nil"
|
end
|
for n, box_def_item in ipairs( ctd.grid_box_def) do
|
if box_def_item.cell_type == cell_type then
|
if n == #ctd.grid_box_def then
|
return 0, nil
|
end
|
return 0, ctd.grid_box_def[n+1]
|
end
|
end
|
return 1, "在容器类型定义中无法获取料格类型 = '"..cell_type.."' 的料格定义"
|
end
|
|
--[[
|
计算料格(如果 container_cell料格里已经有货品,用于补料)能放多少个货品, 根据SKU的 S_COUNT_METHODE 进行可进入料格货品数量
|
ctd -- 容器类型定义
|
cntr_good_weight -- 容器总重量
|
container_cell -- 容器料格对象
|
{"qty","cntr_code","cell_no","cell_type","good_volume","good_weight" }
|
sku -- SKU 物料/货品
|
{ S_ITEM_CODE = "", ...
|
S_COUNT_METHOD -- None -- 无(报错)
|
Weight -- 根据重量计算
|
Volume -- 根据体积计算
|
Limit -- 根据数量限制
|
Mixed -- 根据料箱剩余重量计算可存储货品数量Qw, 根据料箱格剩余体积计算可存储货品数量Qv 取Qw,Qv最小值作为数量返回
|
--]]
|
function wms_cntr.Get_CntrCell_Goods_Qty( ctd, cntr_good_weight, container_cell, sku )
|
local sku_volume, sku_weight, sku_count_method
|
local sku_loading_limit -- SKU 在料格里最多可装载数量
|
local cntr_max_weight
|
|
-- 输入参数判断
|
sku_volume = lua.Get_NumAttrValue( sku.F_VOLUME )
|
sku_weight = lua.Get_NumAttrValue( sku.F_WEIGHT )
|
sku_count_method = lua.Get_StrAttrValue( sku.S_COUNT_METHOD )
|
cntr_max_weight = lua.Get_NumAttrValue( ctd.load_capacity )
|
sku_loading_limit = lua.Get_NumAttrValue( sku.N_LOADING_LIMIT )
|
|
if ( sku_count_method == '' or sku_count_method == "None" ) then
|
return 1, "SKU 编码'"..sku.S_ITEM_CODE.."'的 S_COUNT_METHOD 必须有值且不能为 None!"
|
end
|
|
if (container_cell.cell_type == '' or container_cell.cell_type == nil ) then
|
return 1, "calculate_quantity 参数中cell_type必须有值!"
|
end
|
|
local n
|
local cell_max_volume = 0
|
local cell_max_weigt = 0
|
local cell_goods_qty = lua.Get_NumAttrValue( container_cell.qty ) -- 料格中已经存在的货品数量
|
|
for n = 1, #ctd.grid_box_def do
|
if ( ctd.grid_box_def[n].cell_type == container_cell.cell_type ) then
|
cell_max_volume = lua.Get_NumAttrValue( ctd.grid_box_def[n].volume )
|
cell_max_weigt = lua.Get_NumAttrValue( ctd.grid_box_def[n].weight )
|
if cell_max_weigt <= 0 then
|
-- 如果没定义料格载重就用容器总载重除料格数量
|
if ctd.grid_box_def[n].box_num > 0 then
|
cell_max_weigt = cntr_max_weight/ctd.grid_box_def[n].box_num
|
end
|
end
|
break
|
end
|
end
|
|
if ( ctd.check_capacity or sku_count_method == "Weight" or sku_count_method == "Mixed" ) then
|
-- SKU 必须有重量属性
|
if (sku_weight <= 0) then
|
return 1, "Calculate_Quantity 参数中 SKU 中 F_WEIGHT 必须有值并且是数值类型大于0!"
|
end
|
if ( cell_max_weigt <= 0 ) then
|
return 1, "料格类型'"..container_cell.cell_type.."'没有定义料格承重!"
|
end
|
end
|
if ( sku_count_method == "Volume" or sku_count_method == "Mixed" ) then
|
-- SKU 必须有体积属性
|
if (sku_volume <= 0) then
|
return 1, "Calculate_Quantity 参数中 SKU 中 F_VOLUME 必须有值并且是数值类型大于0!"
|
end
|
if ( cell_max_volume <= 0 ) then
|
return 1, "料格类型'"..container_cell.cell_type.."'没有定义体积!"
|
end
|
end
|
if ( sku_count_method == "Limit" ) then
|
-- SKU 必须有 N_LOADING_LIMIT/容器装载上限 属性
|
if not lua.isTableEmpty( sku.sku_grid_parm ) then
|
nRet, sku_loading_limit = wms_base.GetSKU_LoadingLimit( sku, ctd.ctd_code, container_cell.cell_type )
|
if nRet ~= 0 then
|
return 1, sku_loading_limit
|
end
|
else
|
if (sku_loading_limit <= 0) then
|
return 1, "Calculate_Quantity 参数中 SKU 中 N_LOADING_LIMIT 必须有值并且是数值类型大于0!"
|
end
|
end
|
end
|
|
if ( cell_goods_qty < 0 ) then return 1, "容器'"..container_cell.cntr_code.."' 料格 '"..container_cell.cell_no.."' 的货品数量为负数!" end
|
|
-- V2.0 加 WMS_Volumetric_Ratio/容积率 MDF BY HAN 20250315
|
local v_ratio
|
nRet, v_ratio = wms_base.Get_nConst2( "WMS_Volumetric_Ratio" )
|
if nRet ~= 0 then
|
v_ratio = 1
|
else
|
if ( v_ratio == 0 or v_ratio > 1 ) then v_ratio = 1 end
|
end
|
cell_max_volume = cell_max_volume * v_ratio
|
|
local Qv, Qw, Ql
|
if ( sku_count_method == "Mixed" ) then
|
-- 根据料箱格剩余体积计算可存储货品数量Qv
|
Qv = math.floor(( cell_max_volume - container_cell.good_volume )/sku_volume)
|
if ( Qv < 0 ) then
|
return 1, "calculate_quantity 通过体积计算数量失败! cell_max_volume = "..cell_max_volume.." container_cell_good_volume = "..container_cell.good_volume..
|
" 料箱号 = '"..container_cell.cntr_code.."' 料格号 = "..container_cell.cell_no
|
end
|
|
-- 根据料箱剩余重量计算可存储货品数量Qw
|
if ( ctd.check_capacity ) then
|
Qw = math.floor(( cntr_max_weight - cntr_good_weight )/sku_weight)
|
if ( Qw < 0 ) then
|
return 1, "calculate_quantity 通过重量计算数量失败! cntr_max_weight = "..cntr_max_weight.." cntr_good_weight = "..cntr_good_weight..
|
" 料箱号 = '"..container_cell.cntr_code.."' 料格号 = "..container_cell.cell_no
|
end
|
else
|
return 0, Qv
|
end
|
if ( Qw > Qv ) then return 0, Qv end
|
return 0, Qw
|
elseif ( sku_count_method == "Weight" ) then
|
Qw = math.floor(( cell_max_weigt - container_cell.good_weight )/sku_weight)
|
if ( Qw < 0 ) then
|
return 1, "calculate_quantity 通过重量计算数量失败! cntr_max_weight = "..cntr_max_weight.." cntr_good_weight = "..cntr_good_weight..
|
" 料箱号 = '"..container_cell.cntr_code.."' 料格号 = "..container_cell.cell_no
|
end
|
return 0, Qw
|
elseif ( sku_count_method == "Volume" ) then
|
Qv = math.floor(( cell_max_volume - container_cell.good_volume )/sku_volume)
|
if ( Qv < 0 ) then
|
return 1, "calculate_quantity 通过体积计算数量失败! cell_max_volume = "..cell_max_volume.." container_cell_good_volume = "..container_cell.good_volume..
|
" 料箱号 = '"..container_cell.cntr_code.."' 料格号 = "..container_cell.cell_no
|
end
|
return 0, Qv
|
elseif ( sku_count_method == "Limit" ) then
|
Ql = sku_loading_limit - cell_goods_qty
|
return 0, Ql
|
end
|
return 1, "计数方法'"..sku_count_method.."'目前没支持"
|
end
|
|
--[[
|
容器和货位解绑, 并且释放库存量,这个一般用于实施辅助
|
输入参数:
|
cntr_code -- 容器编码
|
action_src -- 解绑动作来源
|
--]]
|
function wms_cntr.Unbinding( strLuaDEID, cntr_code, action_src )
|
local nRet, strRetInfo, strErr
|
|
if ( cntr_code == nil or cntr_code == '' ) then
|
return 1, "wms_cntr.Unbinding 输入参数 cntr_code 必须有值!"
|
end
|
if ( action_src == nil ) then action_src = '' end
|
|
-- 获取容器是否有绑定货位
|
nRet, loc_code = wms_cntr.Get_Container_Loc( strLuaDEID, cntr_code )
|
if ( nRet ~= 0 ) then
|
return 2, "获取容器位置失败!"..loc_code
|
end
|
if ( loc_code == '' ) then return 0 end
|
|
-- 把解绑方式,解绑来源加到全局变量中,在 Loc_Container 删除后事件上会用到
|
local global_attrs = {
|
{ attr = "N_BINDING_METHOD",value = BINDING_METHOD.Manual },
|
{ attr = "S_ACTION_SRC", value = action_src }
|
}
|
mobox.setGlobalAttr( strLuaDEID, lua.table2str(global_attrs) )
|
|
local strCondition = "S_LOC_CODE = '"..loc_code.."' AND S_CNTR_CODE = '"..cntr_code.."'"
|
-- 删除数据对象【Loc_Container】会触发该数据类的删除后事件,事件会调用函数 wms_ContainerLocAction
|
nRet, strRetInfo = mobox.deleteDataObject( strLuaDEID, "Loc_Container", strCondition )
|
if ( nRet ~= 0) then
|
return nRet, "删除【货位容器绑定】失败! "..strRetInfo
|
end
|
nRet, strRetInfo = wms_inv.After_CntrLoc_UnBinding( strLuaDEID, cntr_code, action_src )
|
if ( nRet ~= 0) then
|
return nRet, "wms_inv.After_CntrLoc_UnBinding 失败! "..strRetInfo
|
end
|
return 0
|
end
|
|
--[[
|
获取容器+容器扩展属性,返回 数据对象字段属性 对象
|
输入参数:
|
cntr_code -- 容器编码
|
--]]
|
function wms_cntr.Get_Container_ExtInfo( strLuaDEID, cntr_code )
|
local nRet, strRetInfo
|
|
local strTable = "TN_Container a LEFT JOIN TN_Container_Ext b ON a.S_CODE = b.S_CNTR_CODE"
|
local strCondition = "a.S_CODE = '"..cntr_code.."'"
|
|
-- 组织查询属性
|
local attr_set = {}
|
local strAttrs = ''
|
local UDF_ATTRS_COUNT = #UDF_ATTRS
|
local CNTR_BASE_ATTRS_COUNT = #CNTR_BASE_ATTRS
|
local CNTR_EXT_BASE_ATTRS_COUNT = #CNTR_EXT_BASE_ATTRS
|
|
for m = 1, CNTR_BASE_ATTRS_COUNT do
|
strAttrs = strAttrs.."a."..CNTR_BASE_ATTRS[m]..","
|
table.insert( attr_set, CNTR_BASE_ATTRS[m] )
|
end
|
for m = 1, CNTR_EXT_BASE_ATTRS_COUNT do
|
strAttrs = strAttrs.."b."..CNTR_EXT_BASE_ATTRS[m]..","
|
table.insert( attr_set, CNTR_EXT_BASE_ATTRS[m] )
|
end
|
for m = 1, UDF_ATTRS_COUNT do
|
strAttrs = strAttrs.."b."..UDF_ATTRS[m]..","
|
table.insert( attr_set, UDF_ATTRS[m] )
|
end
|
|
nRet, strRetInfo = mobox.queryMultiTable( strLuaDEID, lua.trim_laster_char( strAttrs ), strTable, 1, strCondition, "" )
|
if (nRet ~= 0) then
|
return 2,"queryMultiTable 失败!"..strRetInfo
|
end
|
if ( strRetInfo == '' ) then
|
return 1, "容器'"..cntr_code.."不存在!"
|
end
|
local ret_attr = json.decode(strRetInfo)
|
local cntr_ext = {}
|
local n = 1
|
|
-- 获取联表查询属性
|
for m = 1, CNTR_BASE_ATTRS_COUNT do
|
cntr_ext[CNTR_BASE_ATTRS[m]] = ret_attr[1][n]
|
n = n + 1
|
end
|
for m = 1, CNTR_EXT_BASE_ATTRS_COUNT do
|
cntr_ext[CNTR_EXT_BASE_ATTRS[m]] = ret_attr[1][n]
|
n = n + 1
|
end
|
for m = 1, UDF_ATTRS_COUNT do
|
cntr_ext[UDF_ATTRS[m]] = ret_attr[1][n]
|
n = n + 1
|
end
|
return 0, cntr_ext
|
|
end
|
|
return wms_cntr
|