--[[ 版本: 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