--[[
|
编码: JX-API-02
|
名称: 接收入库单并创建入库单及明细
|
作者: kun
|
入口函数:CreateInbound
|
日期: 2025-4-16
|
|
功能:
|
- 根据物料 area_code 对 ITEMS 进行分组,每组创建一张入库单。
|
- 若中间任意校验失败,中止创建流程并返回固定结构。
|
|
输入数据格式:
|
{
|
"S_OP_TYPE":"采购入库",
|
"S_BS_NO": "20250528002",
|
"SourceKey": "",
|
"S_NOTE": "",
|
"ITEMS": [{
|
"S_ITEM_CODE":"A123",
|
"F_QTY":12,
|
"S_EXT_ATTR1":"",
|
"D_PRD_DATE":"",
|
"S_SUPPLIER_NO":"",
|
"S_SUPPLIER_NAME":"",
|
"S_BS_NO":"CS001",
|
"N_BS_ROW_NO":1,
|
"N_ITEM_STATE":"O",
|
"S_EXT_ATTR2":"",
|
"F_WEIGHT": 0.5,
|
"S_EXT_ATTR3":"",
|
"S_EXT_ATTR4":"",
|
"S_EXT_ATTR5":""
|
},
|
{
|
"S_ITEM_CODE":"A234",
|
"F_QTY":12,
|
"S_EXT_ATTR1":"",
|
"D_PRD_DATE":"",
|
"S_SUPPLIER_NO":"",
|
"S_SUPPLIER_NAME":"",
|
"S_BS_NO":"CS002",
|
"N_BS_ROW_NO":2,
|
"N_ITEM_STATE":"O",
|
"S_EXT_ATTR2":"",
|
"F_WEIGHT": 0.5,
|
"S_EXT_ATTR3":"",
|
"S_EXT_ATTR4":"",
|
"S_EXT_ATTR5":""
|
},
|
{
|
"S_ITEM_CODE":"CS001",
|
"F_QTY":12,
|
"S_EXT_ATTR1":"",
|
"D_PRD_DATE":"",
|
"S_SUPPLIER_NO":"",
|
"S_SUPPLIER_NAME":"",
|
"S_BS_NO":"CS003",
|
"N_BS_ROW_NO":3,
|
"N_ITEM_STATE":"O",
|
"S_EXT_ATTR2":"",
|
"F_WEIGHT": 0.5,
|
"S_EXT_ATTR3":"",
|
"S_EXT_ATTR4":"",
|
"S_EXT_ATTR5":""
|
}
|
]
|
}
|
|
--]]
|
|
json = require("json")
|
mobox = require("OILua_JavelinExt")
|
m3 = require("oi_base_mobox")
|
wms_base = require("wms_base")
|
|
function CreateInbound(strLuaDEID)
|
local nRet, inputData
|
local err = {}
|
local result_code_list = {}
|
local errcode = {}
|
local err_msg
|
local inbound_data
|
local strCondition
|
local nRetl,strRetInfo
|
local nRet,wh_code
|
m3.PrintLuaDEInfo(strLuaDEID)
|
|
nRet, inputData = m3.GetSysDataJson(strLuaDEID)
|
if (nRet ~= 0) then
|
table.insert(errcode, "无法获取数据包!")
|
goto continue
|
end
|
|
inbound_data = inputData.ITEMS
|
if not inbound_data or #inbound_data == 0 then
|
table.insert(errcode, "Data 或 ITEMS 不合法!")
|
goto continue
|
end
|
|
if (inputData.S_OP_TYPE == nil or inputData.S_OP_TYPE == "") then
|
table.insert(errcode, "业务来源S_OP_TYPE不能为空或不合法!")
|
goto continue
|
end
|
|
if (inputData.S_BS_NO == nil or inputData.S_BS_NO == "") then
|
table.insert(errcode, "业务来源S_BS_NO不能为空或不合法!")
|
goto continue
|
end
|
|
strCondition = " S_BS_NO = '" .. inputData.S_BS_NO .. "' "
|
nRetl, strRetInfo = mobox.existThisData(strLuaDEID, "Inbound_Order", strCondition)
|
if (nRetl ~= 0) then
|
table.insert(errcode, "调用方法 existThisData 出错" .. inputData.S_BS_NO)
|
goto continue
|
end
|
if (strRetInfo == 'yes') then
|
table.insert(errcode, "来源单号存在" .. inputData.S_BS_NO)
|
goto continue
|
end
|
nRet,wh_code = wms_base.Get_sConst2( "默认工厂标识" )
|
if ( nRet ~= 0 ) then
|
table.insert(errcode, "系统常量:默认工厂标识" .. inputData.S_BS_NO)
|
goto continue
|
end
|
if ( wh_code == '' ) then
|
table.insert(errcode, "系统常量'默认工厂标识'必须有值!" .. inputData.S_BS_NO)
|
goto continue
|
end
|
lua.Debug(strLuaDEID, debug.getinfo(1), " wh_code--->", wh_code)
|
nRet,storer = wms_base.Get_sConst2( "WMS_Default_Storer" )
|
if ( nRet ~= 0 ) then
|
table.insert(errcode, "系统常量:WMS_Default_Storer" .. inputData.S_BS_NO)
|
goto continue
|
end
|
if ( storer == '' ) then
|
table.insert(errcode, "系统常量'WMS_Default_Storer'必须有值!" .. inputData.S_BS_NO)
|
goto continue
|
end
|
lua.Debug(strLuaDEID, debug.getinfo(1), " wh_code--->", wh_code)
|
::continue::
|
|
if #errcode > 0 then
|
local result = {
|
SourceKey = inputData.SourceKey or "",
|
err_code = 1,
|
err_msg = "入库单校验失败:" .. table.concat(errcode, ","),
|
result = nil
|
}
|
mobox.returnValue(strLuaDEID, 1, lua.table2str(result))
|
return
|
end
|
|
-- 分组入库单
|
-- 1. 获取物料的 area_code
|
-- 2. 根据 area_code 分组
|
-- 3. 创建入库单
|
local area_groups = {}
|
for _, item in ipairs(inbound_data) do
|
if not item.S_ITEM_CODE or item.S_ITEM_CODE == "" then
|
table.insert(err, "商品编码不能为空" .. item.S_ITEM_CODE)
|
elseif not item.F_QTY or item.F_QTY == 0 then
|
table.insert(err, "商品数量不能为0" .. item.S_ITEM_CODE)
|
elseif not item.S_BS_NO or item.S_BS_NO == "" then
|
table.insert(err, "来源单号不能为空" .. item.S_ITEM_CODE)
|
elseif not item.N_BS_ROW_NO or item.N_BS_ROW_NO == "" then
|
table.insert(err, "来源行号不能为空" .. item.S_ITEM_CODE)
|
elseif (type(item.N_BS_ROW_NO) ~= "number") then
|
table.insert(err, "来源行号非数字类型" .. item.S_ITEM_CODE)
|
else
|
-- 查询物料
|
-- 物料编码不能为空
|
local cond = "S_ITEM_CODE = '" .. item.S_ITEM_CODE .. "'"
|
local ret1, id, materialAttrs = mobox.getDataObjAttrByKeyAttr(strLuaDEID, "SKU", cond)
|
if ret1 ~= 0 or not materialAttrs then
|
table.insert(err, "获取物料失败:" .. item.S_ITEM_CODE)
|
else
|
local ret2, materialJson = mobox.objAttrsToLuaJson("SKU", materialAttrs)
|
if ret2 ~= 0 then
|
table.insert(err, "物料JSON转换失败:" .. item.S_ITEM_CODE)
|
else
|
local ok, material = pcall(json.decode, materialJson)
|
if not ok or not material or not material.udf01 then
|
table.insert(err, "物料无有效area_code:" .. item.S_ITEM_CODE)
|
else
|
item._material = material
|
local area = material.udf01
|
if not area_groups[area] then
|
area_groups[area] = {}
|
end
|
table.insert(area_groups[area], item)
|
end
|
end
|
end
|
end
|
end
|
|
if #err > 0 then
|
local result = {
|
SourceKey = inputData.SourceKey or "",
|
err_code = 1,
|
err_msg = table.concat(err, ","),
|
result = nil
|
}
|
mobox.returnValue(strLuaDEID, 1, lua.table2str(result))
|
return
|
end
|
|
-- 辅助函数:根据多个字段生成唯一合并键
|
local function get_merge_key(item)
|
return table.concat({
|
item._material.item_code or "",
|
item.S_SUPPLIER_NAME or "",
|
item.S_SUPPLIER_NO or "",
|
tostring(item.N_ITEM_STATE or ""),
|
tostring(item.D_PRD_DATE or ""),
|
tostring(item.F_WEIGHT or 0),
|
item.S_EXT_ATTR2 or "", -- 原产地
|
item.S_EXT_ATTR1 or "",
|
item.S_EXT_ATTR3 or "",
|
item.S_EXT_ATTR4 or "",
|
item.S_EXT_ATTR5 or ""
|
}, "|")
|
end
|
|
for area_code, items in pairs(area_groups) do
|
local header = 'RK' .. os.date("%y%m%d") .. '-'
|
local ret, order_no = mobox.getSerialNumber("入库单", header, 4)
|
if ret ~= 0 then
|
table.insert(err, "申请入库单编码失败:" .. order_no)
|
goto done
|
end
|
-- 创建 ERP 入库单
|
local erp_order = m3.AllocObject(strLuaDEID, "ERP_Inbound_Order")
|
erp_order.state = "发布"
|
erp_order.no = order_no
|
erp_order.op_type = inputData.S_OP_TYPE
|
erp_order.bs_no = inputData.S_BS_NO
|
erp_order.note = inputData.S_NOTE
|
erp_order.wh_code = wh_code
|
erp_order.area_code = area_code
|
erp_order.sour_no = inputData.SourceKey or "" -- 来源单号
|
|
-- 创建 ERP 入库单明细
|
local erp_map = {}
|
|
for _, item in ipairs(items) do
|
local material = item._material
|
local erp_detail = m3.AllocObject(strLuaDEID, "ERP_Inbound_Detail")
|
erp_detail.io_no = order_no -- 入库单号
|
erp_detail.qty = item.F_QTY -- 数量
|
erp_detail.bs_no = item.S_BS_NO -- 来源单号
|
erp_detail.bs_row_no = item.N_BS_ROW_NO -- 来源行号
|
erp_detail.item_state = item.N_ITEM_STATE -- 物料状态
|
erp_detail.prd_date = item.D_PRD_DATE -- 生产日期
|
|
erp_detail.item_code = material.item_code -- 物料编码
|
erp_detail.item_name = material.item_name -- 物料名称
|
erp_detail.s_material = material.udf02 -- 物料材质
|
|
erp_detail.supplier = item.S_SUPPLIER_NO -- 供应商编码
|
erp_detail.supplier_name = item.S_SUPPLIER_NAME -- 供应商名称
|
erp_detail.weight = item.F_WEIGHT or 0 -- 重量
|
erp_detail.ext_attr1 = item.S_EXT_ATTR1 -- 扩展属性1
|
erp_detail.ext_attr2 = item.S_EXT_ATTR2 -- 原产地
|
erp_detail.ext_attr3 = item.S_EXT_ATTR3 -- 扩展属性3
|
erp_detail.ext_attr4 = item.S_EXT_ATTR4 -- 扩展属性4
|
erp_detail.ext_attr5 = item.S_EXT_ATTR5 -- 扩展属性5
|
erp_detail.sour_no = inputData.SourceKey or "" -- 来源单号
|
|
local ret, msg = m3.CreateDataObj(strLuaDEID, erp_detail)
|
if ret ~= 0 then
|
lua.Stop(strLuaDEID, "创建入库单明细失败:" .. msg)
|
return
|
end
|
|
-- 合并 ERP 明细,使用复合键
|
local key = get_merge_key(item)
|
if not erp_map[key] then
|
erp_map[key] = {
|
qty = item.F_QTY, -- 数量
|
io_no = order_no, -- 入库单号
|
supplier = item.S_SUPPLIER_NO, -- 供应商编码
|
supplier_name = item.S_SUPPLIER_NAME, -- 供应商名称
|
item_state = item.N_ITEM_STATE, -- 物料状态
|
prd_date = item.D_PRD_DATE, -- 生产日期
|
weight = item.F_WEIGHT or 0, -- 重量
|
item_name = material.item_name, -- 物料名称
|
item_code = material.item_code, -- 物料编码
|
s_material = material.udf02, -- 物料材质
|
ext_attr1 = item.S_EXT_ATTR1, -- 扩展属性1
|
ext_attr2 = item.S_EXT_ATTR2, -- 扩展属性2 (原产地)
|
ext_attr3 = item.S_EXT_ATTR3, -- 扩展属性3
|
ext_attr4 = item.S_EXT_ATTR4, -- 扩展属性4
|
ext_attr5 = item.S_EXT_ATTR5, -- 扩展属性5
|
}
|
else
|
erp_map[key].qty = erp_map[key].qty + item.F_QTY
|
end
|
end
|
|
local ret3, msg3 = m3.CreateDataObj(strLuaDEID, erp_order)
|
if ret3 ~= 0 then
|
lua.Stop(strLuaDEID, "创建入库单失败:" .. msg3)
|
return
|
end
|
|
-- 创建入库单
|
local order = m3.AllocObject(strLuaDEID, "Inbound_Order")
|
order.state = "发布"
|
order.no = order_no
|
order.bs_no = inputData.S_BS_NO
|
order.op_type = inputData.S_OP_TYPE
|
order.note = inputData.S_NOTE
|
order.area_code = area_code
|
order.wh_code = wh_code
|
order.sour_no = inputData.SourceKey or "" -- 来源单号
|
|
local ret4, msg4 = m3.CreateDataObj(strLuaDEID, order)
|
if ret4 ~= 0 then
|
lua.Stop(strLuaDEID, "创建ERP入库单失败:" .. msg4)
|
return
|
end
|
|
-- 创建合并后的明细
|
for _, v in pairs(erp_map) do
|
local detail = m3.AllocObject(strLuaDEID, "Inbound_Detail")
|
detail.storer = storer
|
detail.io_no = v.io_no
|
detail.item_code = v.item_code
|
detail.item_name = v.item_name
|
detail.qty = v.qty
|
detail.item_state = v.item_state
|
detail.prd_date = v.prd_date
|
detail.supplier = v.supplier
|
detail.supplier_name = v.supplier_name
|
detail.weight = v.weight
|
detail.ext_attr1 = v.ext_attr1
|
detail.ext_attr2 = v.ext_attr2
|
detail.ext_attr3 = v.ext_attr3
|
detail.ext_attr4 = v.ext_attr4
|
detail.ext_attr5 = v.ext_attr5
|
detail.s_material = v.s_material
|
detail.sour_no = inputData.SourceKey or "" -- 来源单号
|
|
local ret5, msg5 = m3.CreateDataObj(strLuaDEID, detail)
|
if ret5 ~= 0 then
|
lua.Stop(strLuaDEID, "创建ERP入库明细失败:" .. msg5)
|
return
|
end
|
end
|
|
::done::
|
end
|
|
|
local final_result
|
if #err > 0 then
|
final_result = {
|
SourceKey = inputData.SourceKey or "",
|
err_code = 1,
|
err_msg = "入库单创建异常:" .. table.concat(err, ","),
|
result = nil
|
}
|
else
|
final_result = {
|
SourceKey = inputData.SourceKey or "",
|
err_code = 0,
|
err_msg = "入库单创建成功!",
|
result = {
|
S_NO = inputData.S_BS_NO
|
}
|
}
|
end
|
|
mobox.returnValue(strLuaDEID, 1, lua.table2str(final_result))
|
end
|