--[[ 编码: GK-API-001 名称: 盘点计划同步 作者: HAN 日期: 2025-1-29 入口函数: SKU_Sync 来源项目: 国科项目 功能说明: 1. 接收来自上游系统的 XML 格式数据,并解析该数据, 创建SKU及SKU_UPC 更新: 2025/06/09 更新了udf01~udf04的属性变更 更改记录: V2.0 HAN 20250402 代码规范 V2.1 Yuanfeng 优化返回结果处理 V2.2 优化错误处理和返回逻辑 V2.3 移除error字段,合并到message中 V2.4 新增SKU_GRID_PARM字段 V2.5 2025-07-01 SKU_GRID料箱格参数优化为根据cell_type 自动同步 SIMPLIFIED CHINESE 0 BM125262 TGKHMB Exceed ABT微孔涂层髋臼杯62mm Exceed ABT微孔涂层髋臼杯62mm Acetabular Shell PC 52 x 62mm 1 10 10 10 0 0 0 A BM-关节 small 120 501927908583 BM141234 CGKHTY Biomet 固定十字型柄胫骨平台假体 75mm Biomet 固定十字型柄胫骨平台假体 75mm 75mm 1 .5 .5 .5 0 0 0 A BM-关节 small 120 1 BM141234 GGKHN1 Biomet 固定十字型柄胫骨平台假体 75mm - 75mm 1 10 10 10 C 0 0 0 A BM-关节 small 120 088030400832 BM141234 TGKHMB Biomet 固定十字型柄胫骨平台假体 75mm Biomet 固定十字型柄胫骨平台假体 75mm 75mm 1 10 10 10 0 0 0 A BM-关节 small 120 088030400832 BM141234 TGKRTH Biomet 固定十字型柄胫骨平台假体 75mm - 75mm 1 10 10 10 0 0 0 A BM-关节 small 120 088030400832 BM141234 TNMGGK Biomet 固定十字型柄胫骨平台假体 75mm - 75mm 1 10 10 10 0 0 0 A BM-关节 small 120 088030400832 BM154720 CGKHTY Oxford第三代单髁膝关节骨水泥型解剖型标准胫骨底板 左膝内侧 Size B Oxford第三代单髁膝关节骨水泥型解剖型标准胫骨底板 左膝内侧 Size B 左膝内侧 Size B 1 10 10 10 0 0 0 A BM-关节 small 120 501927938886 BM154720 GGKHN1 Oxford第三代单髁膝关节骨水泥型解剖型标准胫骨底板 左膝内侧 Size B - 左膝内侧 Size B 1 10 10 10 C 0 0 0 A BM-关节 small 120 501927938886 BM154720 TGKHMB Oxford第三代单髁膝关节骨水泥型解剖型标准胫骨底板 左膝内侧 Size B Oxford第三代单髁膝关节骨水泥型解剖型标准胫骨底板 左膝内侧 Size B 左膝内侧 Size B 1 10 10 10 0 0 0 A BM-关节 small 120 501927938886 BM154720 TNMGGK Oxford第三代单髁膝关节骨水泥型解剖型标准胫骨底板 左膝内侧 Size B - 左膝内侧 Size B 1 10 10 10 0 0 0 A BM-关节 small 120 501927938886 --]] wms_base = require("wms_base") xml = require("oi_base_xml") mobox = require("OILua_JavelinExt") m3 = require("oi_base_mobox") -- 创建统一返回结果(修改后版本,移除error字段) function Create_result(flag, code, msg) return { flag = flag or "success", code = code or "0", message = msg or "" } end -- 创建或更新GK_PROLINE数据(生产线数据) local function create_or_update_proline(strLuaDEID, proline_no, proline_name) local nRet, strRetInfo -- 分配GK_PROLINE对象 local proline = m3.AllocObject(strLuaDEID, "GK_PROLINE") proline.proline_no = proline_no proline.proline_name = proline_name -- 检查是否已存在 local strCondition = string.format("S_PROLINE_NO = '%s'", proline_no) local nRet, id, strRetInfo = mobox.getDataObjAttrByKeyAttr(strLuaDEID, "GK_PROLINE", strCondition) if nRet > 1 then return 1, "检查GK_PROLINE是否存在时失败: " .. strRetInfo end if nRet == 1 then -- 不存在,创建新记录 nRet, strRetInfo = m3.CreateDataObj(strLuaDEID, proline) if nRet ~= 0 then return 1, "创建GK_PROLINE失败: " .. strRetInfo end else -- 已存在,更新记录 local update_proline_obj = {{ id = id, attrs = {{ attr = "S_PROLINE_NAME", value = proline_name }} }} nRet, strRetInfo = mobox.updateDataObj(strLuaDEID, "GK_PROLINE", lua.table2str(update_proline_obj)) if nRet ~= 0 then return 1, "更新GK_PROLINE失败: " .. strRetInfo end end return 0, strRetInfo end -- 创建SKU_UPC local function create_sku_upc(strLuaDEID, storer, item_code, upc_code) local nRet, strRetInfo if (upc_code == '' or upc_code == nil) then return 0 end local sku_upc = m3.AllocObject(strLuaDEID, "SKU_UPC") sku_upc.storer = storer sku_upc.item_code = item_code sku_upc.upc_code = upc_code nRet, strRetInfo = m3.CreateDataObj(strLuaDEID, sku_upc) return nRet, strRetInfo end -- 新增sku_grid_parm JSON字符串,在SKU 创建的时候插入json数据 local function build_sku_grid_parm(ctd_code, sku_input_data, cell_type) -- 如果cell_type为空则跳过 if not cell_type or cell_type == "" then return "" end -- 定义基础json框架结构(放在数组中) local grid_def = {{ ctd_code = ctd_code, cell_def = {} }} -- 根据cell_type确定处理范围 local types_to_process = {} if cell_type == "A" then types_to_process = {"A"} elseif cell_type == "B" then types_to_process = {"A", "B"} elseif cell_type == "C" then types_to_process = {"A", "B", "C"} elseif cell_type == "D" then types_to_process = {"A", "B", "C", "D"} elseif cell_type == "E" then types_to_process = {"A", "B", "C", "D", "E"} elseif cell_type == "F" then types_to_process = {"A", "B", "C", "D", "E", "F"} else -- 未知类型,默认只处理A类型 types_to_process = {"A"} end -- 定义料箱类型与对应字段的映射 local grid_mapping = { A = {loading_limit = sku_input_data.maxCount}, B = {loading_limit = sku_input_data.bMaxCount}, C = {loading_limit = sku_input_data.cMaxCount}, D = {loading_limit = sku_input_data.dMaxCount}, E = {loading_limit = sku_input_data.eMaxCount}, F = {loading_limit = sku_input_data.fMaxCount} } -- 构建cell_def数组 for _, type_key in ipairs(types_to_process) do local grid = grid_mapping[type_key] local limit = lua.Get_NumAttrValue(grid.loading_limit) or 0 if limit > 0 then -- 只有当限制值大于0时才添加 table.insert(grid_def[1].cell_def, { cell_type = type_key, loading_limit = limit, load_capacity = limit }) end end lua.DebugEx(strLuaDEID, "grid", grid_def) return lua.table2str(grid_def) end -- 创建/更新SKU对应的货品料箱格参数 -- skuModel 是数据库定义的数据模型sku,也就是Alloc所创建的SKU对象。 local function create_or_update_sku_gridbox(strLuaDEID, skuModel, sku_input_data) local strRetInfo -- 获取默认容器类型编码 local nConstRet, CONST_CTD_CODE = wms_base.Get_sConst2("WMS_Default_CNTR_Type") if nConstRet ~= 0 then return 1, "获取默认容器类型定义编码失败: " .. CONST_CTD_CODE end -- 如果cell_type为空则跳过 if not skuModel.cell_type or skuModel.cell_type == "" then return 0, "cell_type为空,跳过料箱格参数处理" end -- 根据cell_type确定处理范围 local types_to_process = {} if skuModel.cell_type == "A" then types_to_process = {"A"} elseif skuModel.cell_type == "B" then types_to_process = {"A", "B"} elseif skuModel.cell_type == "C" then types_to_process = {"A", "B", "C"} elseif skuModel.cell_type == "D" then types_to_process = {"A", "B", "C", "D"} elseif skuModel.cell_type == "E" then types_to_process = {"A", "B", "C", "D", "E"} elseif skuModel.cell_type == "F" then types_to_process = {"A", "B", "C", "D", "E", "F"} else -- 未知类型,默认只处理A类型 types_to_process = {"A"} end -- 定义料箱格类型与对应字段的映射 local gridbox_types = { A = sku_input_data.maxCount, B = sku_input_data.bMaxCount, C = sku_input_data.cMaxCount, D = sku_input_data.dMaxCount, E = sku_input_data.eMaxCount, F = sku_input_data.fMaxCount } -- 处理每种料箱格类型 for _, type_key in ipairs(types_to_process) do local loading_limit = lua.Get_NumAttrValue(gridbox_types[type_key]) or 0 if loading_limit <= 0 then -- 只有当限制值大于0时才处理 goto continue end -- 精确查询该类型的料箱格记录 local strCondition = string.format( "S_ITEM_CODE = '%s' AND S_STORER = '%s' AND S_CTD_CODE='%s' AND S_CELL_TYPE='%s'", skuModel.item_code, skuModel.storer, CONST_CTD_CODE, type_key) local nRet, existing_records = m3.GetDataObjByCondition(strLuaDEID, "SKU_GridBox_Parm", strCondition) if nRet == 0 then -- 更新现有记录 local update_gridbox_obj = {{ id = existing_records.id, attrs = {{ attr = "N_LOADING_LIMIT", value = loading_limit }} }} nRet, strRetInfo = mobox.updateDataObj(strLuaDEID, "SKU_GridBox_Parm", lua.table2str(update_gridbox_obj)) if nRet ~= 0 then return 1, string.format("更新%s类型料箱格属性失败: %s", type_key, strRetInfo) end elseif nRet == 1 then -- 创建新记录 local gridbox = m3.AllocObject(strLuaDEID, "SKU_GridBox_Parm") gridbox.item_code = skuModel.item_code gridbox.storer = skuModel.storer gridbox.ctd_code = CONST_CTD_CODE gridbox.loading_limit = loading_limit gridbox.cell_type = type_key nRet, strRetInfo = m3.CreateDataObj(strLuaDEID, gridbox) if nRet ~= 0 then return 1, string.format("创建%s类型料箱格失败: %s", type_key, strRetInfo) end else -- 查询出错 return 1, string.format("查询%s类型料箱格记录失败: %s", type_key, existing_records or "未知错误") end ::continue:: end return 0, "料箱格参数处理完成" end -- 创建或更新SKU主数据 local function create_sku(strLuaDEID, sku_input_data) local nRet, strRetInfo local err_msg = '' -- 获取系统常量 -- 获取默认容器类型编码 local nConstRet, CONST_CTD_CODE = wms_base.Get_sConst2("WMS_Default_CNTR_Type") if nConstRet ~= 0 then return 1, "获取默认容器类型定义编码失败: " .. CONST_CTD_CODE end -- 新增SKU_grid_param local sku_grid_parm = build_sku_grid_parm(CONST_CTD_CODE, sku_input_data, sku_input_data.cidtype) lua.DebugEx(strLuaDEID, "sku_grid_parm", sku_grid_parm) -- 首先检查SKU是否已存在 local strCondition = string.format("S_ITEM_CODE = '%s' AND S_STORER = '%s'", sku_input_data.skuId, sku_input_data.storerId) local nRet, existing_sku = m3.GetDataObjByCondition(strLuaDEID, "SKU", strCondition) -- lua.DebugEx(strLuaDEID, "获取条件查询:", existing_sku) if nRet > 1 then return 1, "检查SKU是否存在时失败: " .. (existing_sku or "未知错误") end -- 分配SKU对象并设置属性 local sku = m3.AllocObject(strLuaDEID, "SKU") sku.item_code = sku_input_data.skuId sku.storer = sku_input_data.storerId sku.short_name = sku_input_data.skuName sku.item_name = sku_input_data.skuDec sku.spec = sku_input_data.spec sku.unit = sku_input_data.goodsUnit sku.long = lua.Get_NumAttrValue(sku_input_data.length) or 0 sku.middle = lua.Get_NumAttrValue(sku_input_data.width) or 0 sku.short = lua.Get_NumAttrValue(sku_input_data.height) or 0 sku.count_method = "Limit" sku.abc_type = sku_input_data.abcType or "" sku.is_life_mgt = (sku_input_data.isBatchMgr == "1" and 'Y') or 'N' sku.is_sn_mgt = (sku_input_data.isSnMgr == "1" and 'Y') or 'N' sku.img_url = sku_input_data.imgUrl or "" sku.cell_type = sku_input_data.cidtype sku.item_type = sku_input_data.skuType sku.loading_limit = lua.Get_NumAttrValue(sku_input_data.maxCount) or 0 sku.udf01 = sku_input_data.productLine or "" sku.udf03 = sku_input_data.isSnStorageMgr or "" sku.udf02 = sku_input_data.storageConditions or "" sku.udf04 = sku_input_data.packageCode or "" sku.udf05 = lua.Get_NumAttrValue(sku_input_data.packageQty) or 0 sku.sku_grid_parm = sku_grid_parm; -- lua.DebugEx(strLuaDEID, "更新/创建数据结果:", sku) if nRet == 1 then -- SKU不存在,创建新记录 nRet, strRetInfo = m3.CreateDataObj(strLuaDEID, sku) if nRet ~= 0 then return 1, "创建SKU失败: " .. strRetInfo .. " skuId = " .. sku_input_data.skuId end else -- SKU已存在,更新记录 local update_sku_obj = {{ id = existing_sku.id, attrs = {{ attr = "S_ITEM_NAME", value = sku.item_name }, { attr = "S_SPEC", value = sku.spec }, { attr = "S_ITEM_TYPE", value = sku.item_type }, { attr = "S_UNIT", value = sku.unit }, { attr = "S_SHORT_NAME", value = sku.short_name }, { attr = "S_ABCTYPE", value = sku.abc_type }, { attr = "C_ISSNMGT", value = sku.is_sn_mgt }, { attr = "C_ISLIFEMGT", value = sku.is_life_mgt }, { attr = "S_IMG_URL", value = sku.img_url }, { attr = "S_CELL_TYPE", value = sku.cell_type }, { attr = "N_LOADING_LIMIT", value = sku.loading_limit }, { attr = "F_LONG", value = sku.long }, { attr = "F_MIDDLE", value = sku.middle }, { attr = "F_SHORT", value = sku.short }, { attr = "S_UDF01", value = sku.udf01 }, { attr = "S_UDF02", value = sku.udf02 }, { attr = "S_UDF03", value = sku.udf03 }, { attr = "S_UDF04", value = sku.udf04 }, { attr = "S_UDF05", value = sku.udf05 }, { attr = "S_SKU_GRID_PARM", value = sku.sku_grid_parm }} }} nRet, strRetInfo = mobox.updateDataObj(strLuaDEID, "SKU", lua.table2str(update_sku_obj)) -- lua.DebugEx(strLuaDEID, "更新返回值", nRet) if nRet ~= 0 then return 1, "更新SKU属性失败: " .. strRetInfo end end -- 处理产品线数据 if sku_input_data.productLine and sku_input_data.productLine ~= "" then local proline_no = sku_input_data.productLine local proline_name = string.match(proline_no, "KH%-(.+)") or proline_no nRet, strRetInfo = create_or_update_proline(strLuaDEID, proline_no, proline_name) if nRet ~= 0 then return 1, "处理产品线数据失败: " .. strRetInfo end end -- 处理SKU_UPC条码 local upc_codes = {sku_input_data.sptm, sku_input_data.barcode1, sku_input_data.barcode2, sku_input_data.barcode3, sku_input_data.barcode_pk, sku_input_data.upc} for _, upc_code in ipairs(upc_codes) do if upc_code and upc_code ~= '' then nRet, strRetInfo = create_sku_upc(strLuaDEID, sku.storer, sku.item_code, upc_code) if nRet ~= 0 then return 1, "创建SKU_UPC失败: " .. strRetInfo .. " UPC: " .. upc_code end end end -- 处理SKU_GridBox_Parm料箱格参数 nRet, strRetInfo = create_or_update_sku_gridbox(strLuaDEID, sku, sku_input_data) if nRet ~= 0 then return 1, "处理SKU_GridBox_Parm失败: " .. strRetInfo end return 0 end -- Main函数 function SKU_Sync(strLuaDEID) -- 初始化最终结果 local FinalRes = Create_result() -- 1. 获取xml数据包 local nRet, soap_xml = mobox.getCurEditDataPacket(strLuaDEID) if nRet ~= 0 then FinalRes = Create_result("failure", "201", "无法获取数据包: " .. soap_xml) local xml_result = xml.json_to_xml(FinalRes, "response") mobox.returnValue(strLuaDEID, 0, xml_result, 0) lua.Stop(strLuaDEID, "获取数据包失败", FinalRes) return end -- 2. 解析xml local nRet, parsed_data = xml.parse(soap_xml) if nRet ~= 0 then FinalRes = Create_result("failure", "202", "xml格式非法") local xml_result = xml.json_to_xml(FinalRes, "response") mobox.returnValue(strLuaDEID, 0, xml_result, 0) lua.Stop(strLuaDEID, "xml格式非法", FinalRes) return end -- 3. 提取SKU数据 local sku_data = parsed_data.Envelope.Body.inCommodityReq.COMMODITY_Input.InputParameters.COMMODITY_TB if not sku_data or not sku_data.COMMODITY_TB_ITEM then FinalRes = Create_result("failure", "203", "xml数据格式错误,缺少COMMODITY_TB_ITEM") local xml_result = xml.json_to_xml(FinalRes, "response") mobox.returnValue(strLuaDEID, 0, xml_result, 0) lua.Stop(strLuaDEID, "xml数据格式错误", FinalRes) return end -- 4. 统一处理:确保sku_items是数组 local sku_items = sku_data.COMMODITY_TB_ITEM if sku_items[1] == nil then sku_items = {sku_items} end -- 5. 遍历所有SKU数据 for i = 1, #sku_items do local sku_item = sku_items[i] -- 创建SKU及其UPC local nRet, err_msg = create_sku(strLuaDEID, sku_item) if nRet ~= 0 then wms_base.Warning(strLuaDEID, 1, 601, err_msg, "从GK-WMS系统同步SKU信息") FinalRes = Create_result("failure", "204", "SKU同步失败: " .. err_msg) local xml_result = xml.json_to_xml(FinalRes, "response") mobox.returnValue(strLuaDEID, 0, xml_result, 0) lua.Stop(strLuaDEID, "SKU同步失败: " .. sku_item.skuId, FinalRes) return end end -- 6. 返回成功 FinalRes = Create_result("success", "0", "SKU同步成功") local xml_result = xml.json_to_xml(FinalRes, "response") mobox.returnValue(strLuaDEID, 0, xml_result, 0) end