Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
J
jilinzhongdianrenqun
概览
Overview
Details
Activity
Cycle Analytics
版本库
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
问题
0
Issues
0
列表
Board
标记
里程碑
合并请求
0
Merge Requests
0
CI / CD
CI / CD
流水线
作业
日程表
图表
维基
Wiki
代码片段
Snippets
成员
Members
Collapse sidebar
Close sidebar
活动
图像
聊天
创建新问题
作业
提交
Issue Boards
Open sidebar
吴超
jilinzhongdianrenqun
Commits
96e321fd
Commit
96e321fd
authored
Dec 31, 2025
by
zhangtw
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
导入新建类与模板
parent
9d95b93c
隐藏空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
551 行增加
和
0 行删除
+551
-0
src/main/java/com/scpyun/platform/jilinsscgsdp/bean/entity/InboundImp.java
+30
-0
src/main/java/com/scpyun/platform/jilinsscgsdp/utils/InboundFileListener.java
+521
-0
src/main/resources/KeyInboundImp.xlsx
+0
-0
没有找到文件。
src/main/java/com/scpyun/platform/jilinsscgsdp/bean/entity/InboundImp.java
0 → 100644
View file @
96e321fd
package
com
.
scpyun
.
platform
.
jilinsscgsdp
.
bean
.
entity
;
import
com.alibaba.excel.annotation.ExcelProperty
;
import
lombok.Data
;
@Data
public
class
InboundImp
{
@ExcelProperty
(
value
=
"入库单号"
,
index
=
0
)
private
String
inbound_no
;
@ExcelProperty
(
value
=
"批次号"
,
index
=
1
)
private
String
batch_no
;
@ExcelProperty
(
value
=
"入库日期"
,
index
=
2
)
private
String
inbound_date
;
@ExcelProperty
(
value
=
"存放位置"
,
index
=
3
)
private
String
storage_location
;
@ExcelProperty
(
value
=
"备注"
,
index
=
4
)
private
String
remark
;
@ExcelProperty
(
value
=
"物料编号"
,
index
=
5
)
private
String
material_code
;
@ExcelProperty
(
value
=
"物料名称"
,
index
=
6
)
private
String
material_name
;
@ExcelProperty
(
value
=
"入库数量"
,
index
=
7
)
private
String
inbound_quantity
;
@ExcelProperty
(
value
=
"单价"
,
index
=
8
)
private
String
unit_price
;
@ExcelProperty
(
value
=
"生产日期"
,
index
=
9
)
private
String
production_date
;
@ExcelProperty
(
value
=
"有效期至"
,
index
=
10
)
private
String
expiry_date
;
}
src/main/java/com/scpyun/platform/jilinsscgsdp/utils/InboundFileListener.java
0 → 100644
View file @
96e321fd
package
com
.
scpyun
.
platform
.
jilinsscgsdp
.
utils
;
import
com.alibaba.excel.context.AnalysisContext
;
import
com.alibaba.excel.event.AnalysisEventListener
;
import
com.scpyun.base.core.utils.StringUtils
;
import
com.scpyun.base.core.utils.UUIDUtil
;
import
com.scpyun.base.db.service.CommonService
;
import
com.scpyun.platform.jilinsscgsdp.bean.entity.InboundImp
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
java.math.BigDecimal
;
import
java.text.ParseException
;
import
java.text.SimpleDateFormat
;
import
java.util.*
;
import
java.util.concurrent.atomic.AtomicInteger
;
public
class
InboundFileListener
extends
AnalysisEventListener
<
InboundImp
>
{
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
InboundFileListener
.
class
);
private
static
final
int
BATCH_COUNT
=
200
;
private
static
final
int
GROUP_BATCH_SIZE
=
50
;
// 每批处理50个入库单
private
List
<
InboundImp
>
cached
=
new
ArrayList
<>(
BATCH_COUNT
);
private
AtomicInteger
insertCount
=
new
AtomicInteger
(
0
);
private
AtomicInteger
errorCount
=
new
AtomicInteger
(
0
);
private
AtomicInteger
inboundCount
=
new
AtomicInteger
(
0
);
// 入库单计数
private
CommonService
commonService
;
private
String
namespace
;
private
Map
<
String
,
Object
>
param
;
private
List
<
String
>
errInfo
=
new
ArrayList
<>();
private
Map
<
String
,
Object
>
materialMap
;
// 用于存储按入库单号分组的明细数据
private
Map
<
String
,
List
<
InboundImp
>>
inboundGroupMap
=
new
HashMap
<>();
private
Map
<
String
,
Object
>
user
=
null
;
private
SimpleDateFormat
dateFormat
=
new
SimpleDateFormat
(
"yyyy-MM-dd"
);
public
InboundFileListener
(
CommonService
commonService
,
String
namespace
,
Map
<
String
,
Object
>
param
)
{
this
.
commonService
=
commonService
;
this
.
namespace
=
namespace
;
this
.
param
=
param
;
user
=
(
Map
<
String
,
Object
>)
param
.
get
(
"_user"
);
// 初始化日期格式
dateFormat
.
setLenient
(
false
);
// 初始化物料映射
initMaterialMap
();
}
/**
* 初始化物料映射
*/
private
void
initMaterialMap
()
{
try
{
List
<
Map
<
String
,
Object
>>
materialList
=
commonService
.
findList
(
namespace
+
"getMaterialMap"
,
null
);
materialMap
=
new
HashMap
<>();
for
(
Map
<
String
,
Object
>
material
:
materialList
)
{
String
code
=
String
.
valueOf
(
material
.
get
(
"material_code"
));
if
(
StringUtils
.
isNotEmpty
(
code
))
{
materialMap
.
put
(
code
,
material
);
}
}
log
.
info
(
"初始化物料映射完成,共 {} 条记录"
,
materialMap
.
size
());
}
catch
(
Exception
e
)
{
log
.
error
(
"初始化物料映射异常"
,
e
);
materialMap
=
new
HashMap
<>();
}
}
@Override
public
void
invoke
(
InboundImp
data
,
AnalysisContext
context
)
{
try
{
// 数据校验
if
(
isValidInbound
(
data
))
{
cached
.
add
(
data
);
// 按入库单号和批次号分组
String
groupKey
=
getGroupKey
(
data
);
// 初始化分组列表
if
(!
inboundGroupMap
.
containsKey
(
groupKey
))
{
inboundGroupMap
.
put
(
groupKey
,
new
ArrayList
<>());
}
inboundGroupMap
.
get
(
groupKey
).
add
(
data
);
}
else
{
errorCount
.
incrementAndGet
();
errInfo
.
add
(
"行数据校验失败: "
+
data
.
getInbound_no
()
+
"-"
+
data
.
getMaterial_code
());
}
if
(
cached
.
size
()
>=
BATCH_COUNT
)
{
saveBatch
();
cached
.
clear
();
}
}
catch
(
Exception
e
)
{
errorCount
.
incrementAndGet
();
errInfo
.
add
(
"解析异常: "
+
data
.
getInbound_no
()
+
"-"
+
data
.
getMaterial_code
()
+
":"
+
e
.
getMessage
());
log
.
error
(
"解析入库导入行异常"
,
e
);
}
}
@Override
public
void
doAfterAllAnalysed
(
AnalysisContext
context
)
{
if
(!
cached
.
isEmpty
())
{
saveBatch
();
cached
.
clear
();
}
// 处理所有分组的数据
processInboundGroupsTransactional
();
}
/**
* 获取分组键(入库单号 + 批次号)
*/
private
String
getGroupKey
(
InboundImp
data
)
{
String
inboundNo
=
StringUtils
.
isNotEmpty
(
data
.
getInbound_no
())
?
data
.
getInbound_no
().
trim
()
:
""
;
String
batchNo
=
StringUtils
.
isNotEmpty
(
data
.
getBatch_no
())
?
data
.
getBatch_no
().
trim
()
:
"DEFAULT"
;
return
inboundNo
+
"|"
+
batchNo
;
}
/**
* 事务性批量处理入库单
*/
private
void
processInboundGroupsTransactional
()
{
if
(
inboundGroupMap
.
isEmpty
())
{
return
;
}
List
<
String
>
groupKeys
=
new
ArrayList
<>(
inboundGroupMap
.
keySet
());
// 按批次处理,避免内存溢出
for
(
int
i
=
0
;
i
<
groupKeys
.
size
();
i
+=
GROUP_BATCH_SIZE
)
{
int
end
=
Math
.
min
(
i
+
GROUP_BATCH_SIZE
,
groupKeys
.
size
());
List
<
String
>
batchGroupKeys
=
groupKeys
.
subList
(
i
,
end
);
try
{
// 开启事务处理一批入库单
processBatchTransactional
(
batchGroupKeys
);
}
catch
(
Exception
e
)
{
log
.
error
(
"批量处理入库单异常"
,
e
);
// 当前批次失败,尝试单个处理
for
(
String
groupKey
:
batchGroupKeys
)
{
try
{
processSingleInboundGroup
(
groupKey
);
}
catch
(
Exception
ex
)
{
errorCount
.
incrementAndGet
();
errInfo
.
add
(
"入库单处理失败: "
+
groupKey
+
":"
+
ex
.
getMessage
());
}
}
}
}
}
/**
* 批量处理事务
*/
private
void
processBatchTransactional
(
List
<
String
>
groupKeys
)
{
List
<
Map
<
String
,
Object
>>
masterList
=
new
ArrayList
<>();
Map
<
String
,
String
>
inboundIdMap
=
new
HashMap
<>();
// groupKey -> inboundId
List
<
Map
<
String
,
Object
>>
detailList
=
new
ArrayList
<>();
// 第一步:创建入库单主表和明细数据
for
(
String
groupKey
:
groupKeys
)
{
List
<
InboundImp
>
inboundList
=
inboundGroupMap
.
get
(
groupKey
);
if
(
inboundList
==
null
||
inboundList
.
isEmpty
())
{
continue
;
}
InboundImp
firstRecord
=
inboundList
.
get
(
0
);
Map
<
String
,
Object
>
inboundMaster
=
createInboundMaster
(
firstRecord
);
if
(
inboundMaster
==
null
)
{
throw
new
RuntimeException
(
"创建入库单主表失败: "
+
groupKey
);
}
String
inboundId
=
(
String
)
inboundMaster
.
get
(
"id"
);
inboundIdMap
.
put
(
groupKey
,
inboundId
);
masterList
.
add
(
inboundMaster
);
// 创建明细数据
for
(
InboundImp
detail
:
inboundList
)
{
Map
<
String
,
Object
>
inboundDetail
=
createInboundDetail
(
detail
,
inboundId
);
if
(
inboundDetail
!=
null
)
{
detailList
.
add
(
inboundDetail
);
}
}
}
if
(
masterList
.
isEmpty
())
{
return
;
}
// 第二步:批量插入入库单主表
batchInsertInboundMasters
(
masterList
);
inboundCount
.
addAndGet
(
masterList
.
size
());
// 第三步:批量插入入库明细
if
(!
detailList
.
isEmpty
())
{
batchInsertInboundDetails
(
detailList
);
insertCount
.
addAndGet
(
detailList
.
size
());
}
// 第四步:批量更新物料库存
batchUpdateMaterialStock
(
detailList
);
}
/**
* 单个入库单组处理
*/
private
void
processSingleInboundGroup
(
String
groupKey
)
{
List
<
InboundImp
>
inboundList
=
inboundGroupMap
.
get
(
groupKey
);
if
(
inboundList
==
null
||
inboundList
.
isEmpty
())
{
return
;
}
InboundImp
firstRecord
=
inboundList
.
get
(
0
);
Map
<
String
,
Object
>
inboundMaster
=
createInboundMaster
(
firstRecord
);
if
(
inboundMaster
==
null
)
{
throw
new
RuntimeException
(
"创建入库单主表失败: "
+
groupKey
);
}
// 插入主表
String
inboundId
=
insertInboundMaster
(
inboundMaster
);
if
(
inboundId
==
null
)
{
throw
new
RuntimeException
(
"插入入库单主表失败: "
+
groupKey
);
}
inboundCount
.
incrementAndGet
();
// 插入明细
for
(
InboundImp
detail
:
inboundList
)
{
Map
<
String
,
Object
>
inboundDetail
=
createInboundDetail
(
detail
,
inboundId
);
if
(
inboundDetail
!=
null
)
{
insertInboundDetail
(
inboundDetail
);
insertCount
.
incrementAndGet
();
}
}
}
/**
* 批量插入入库单主表
*/
private
void
batchInsertInboundMasters
(
List
<
Map
<
String
,
Object
>>
inboundMasters
)
{
if
(
inboundMasters
==
null
||
inboundMasters
.
isEmpty
())
{
return
;
}
try
{
Map
<
String
,
Object
>
batchParam
=
new
HashMap
<>();
batchParam
.
put
(
"list"
,
inboundMasters
);
batchParam
.
put
(
"_user"
,
user
);
commonService
.
insert
(
namespace
+
"batchInsertInboundMasters"
,
batchParam
);
}
catch
(
Exception
e
)
{
log
.
error
(
"批量插入入库单主表异常"
,
e
);
throw
new
RuntimeException
(
"批量插入入库单主表失败"
,
e
);
}
}
/**
* 批量插入入库明细
*/
private
void
batchInsertInboundDetails
(
List
<
Map
<
String
,
Object
>>
inboundDetails
)
{
if
(
inboundDetails
==
null
||
inboundDetails
.
isEmpty
())
{
return
;
}
try
{
Map
<
String
,
Object
>
batchParam
=
new
HashMap
<>();
batchParam
.
put
(
"list"
,
inboundDetails
);
batchParam
.
put
(
"_user"
,
user
);
commonService
.
insert
(
namespace
+
"batchInsertInboundDetails"
,
batchParam
);
}
catch
(
Exception
e
)
{
log
.
error
(
"批量插入入库明细异常"
,
e
);
throw
new
RuntimeException
(
"批量插入入库明细失败"
,
e
);
}
}
/**
* 批量更新物料库存
*/
private
void
batchUpdateMaterialStock
(
List
<
Map
<
String
,
Object
>>
inboundDetails
)
{
if
(
inboundDetails
==
null
||
inboundDetails
.
isEmpty
())
{
return
;
}
try
{
// 按物料ID分组汇总数量
Map
<
String
,
BigDecimal
>
materialQuantityMap
=
new
HashMap
<>();
for
(
Map
<
String
,
Object
>
detail
:
inboundDetails
)
{
String
materialId
=
(
String
)
detail
.
get
(
"material_id"
);
BigDecimal
quantity
=
(
BigDecimal
)
detail
.
get
(
"inbound_quantity"
);
if
(
materialId
!=
null
&&
quantity
!=
null
)
{
materialQuantityMap
.
merge
(
materialId
,
quantity
,
BigDecimal:
:
add
);
}
}
// 批量更新
List
<
Map
<
String
,
Object
>>
updateList
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
BigDecimal
>
entry
:
materialQuantityMap
.
entrySet
())
{
Map
<
String
,
Object
>
updateParam
=
new
HashMap
<>();
updateParam
.
put
(
"material_id"
,
entry
.
getKey
());
updateParam
.
put
(
"quantity"
,
entry
.
getValue
());
updateParam
.
put
(
"update_time"
,
new
Date
());
updateParam
.
put
(
"_user"
,
user
);
updateList
.
add
(
updateParam
);
}
if
(!
updateList
.
isEmpty
())
{
Map
<
String
,
Object
>
batchParam
=
new
HashMap
<>();
batchParam
.
put
(
"list"
,
updateList
);
batchParam
.
put
(
"_user"
,
user
);
commonService
.
update
(
namespace
+
"batchUpdateMaterialStock"
,
batchParam
);
}
}
catch
(
Exception
e
)
{
log
.
error
(
"批量更新物料库存异常"
,
e
);
throw
new
RuntimeException
(
"批量更新物料库存失败"
,
e
);
}
}
/**
* 创建入库单主表记录
*/
private
Map
<
String
,
Object
>
createInboundMaster
(
InboundImp
data
)
{
try
{
Map
<
String
,
Object
>
master
=
new
HashMap
<>();
master
.
put
(
"id"
,
UUIDUtil
.
getUUID
());
master
.
put
(
"inbound_no"
,
data
.
getInbound_no
());
master
.
put
(
"batch_no"
,
data
.
getBatch_no
());
master
.
put
(
"inbound_type"
,
1
);
master
.
put
(
"inbound_status"
,
1
);
// 1-已入库
// 处理入库日期
Date
inboundDate
=
null
;
if
(
StringUtils
.
isNotEmpty
(
data
.
getInbound_date
()))
{
try
{
inboundDate
=
dateFormat
.
parse
(
data
.
getInbound_date
().
trim
());
}
catch
(
ParseException
e
)
{
log
.
warn
(
"日期格式解析失败: {}"
,
data
.
getInbound_date
());
}
}
if
(
inboundDate
==
null
)
{
inboundDate
=
new
Date
();
}
master
.
put
(
"inbound_date"
,
inboundDate
);
master
.
put
(
"is_used"
,
1
);
master
.
put
(
"storage_location"
,
data
.
getStorage_location
());
master
.
put
(
"remark"
,
data
.
getRemark
());
master
.
put
(
"create_by"
,
user
.
get
(
"id"
));
master
.
put
(
"create_time"
,
new
Date
());
master
.
put
(
"_user"
,
user
);
return
master
;
}
catch
(
Exception
e
)
{
log
.
error
(
"创建入库单主表异常"
,
e
);
return
null
;
}
}
/**
* 创建入库明细记录
*/
private
Map
<
String
,
Object
>
createInboundDetail
(
InboundImp
data
,
String
inboundId
)
{
try
{
// 检查物料是否存在
Map
<
String
,
Object
>
materialTempMap
=
(
Map
<
String
,
Object
>)
materialMap
.
get
(
data
.
getMaterial_code
());
if
(
materialTempMap
==
null
)
{
log
.
warn
(
"物料 {} 不存在,跳过该明细"
,
data
.
getMaterial_code
());
errInfo
.
add
(
"物料不存在: "
+
data
.
getMaterial_code
());
return
null
;
}
Map
<
String
,
Object
>
detail
=
new
HashMap
<>();
detail
.
put
(
"id"
,
UUIDUtil
.
getUUID
());
detail
.
put
(
"inbound_id"
,
inboundId
);
detail
.
put
(
"material_id"
,
materialTempMap
.
get
(
"id"
));
// 物料名称优先使用Excel中的,否则使用系统已有的
String
materialName
=
StringUtils
.
isNotEmpty
(
data
.
getMaterial_name
())
?
data
.
getMaterial_name
().
trim
()
:
(
String
)
materialTempMap
.
get
(
"material_name"
);
detail
.
put
(
"material_name"
,
materialName
);
detail
.
put
(
"material_code"
,
data
.
getMaterial_code
());
detail
.
put
(
"inbound_type"
,
1
);
detail
.
put
(
"is_used"
,
1
);
// 转换入库数量
BigDecimal
inboundQuantity
=
BigDecimal
.
ZERO
;
try
{
if
(
StringUtils
.
isNotEmpty
(
data
.
getInbound_quantity
()))
{
inboundQuantity
=
new
BigDecimal
(
data
.
getInbound_quantity
().
trim
());
}
}
catch
(
Exception
e
)
{
log
.
warn
(
"数量格式转换失败: {}"
,
data
.
getInbound_quantity
());
inboundQuantity
=
BigDecimal
.
ZERO
;
}
detail
.
put
(
"inbound_quantity"
,
inboundQuantity
);
// 转换单价
BigDecimal
unitPrice
=
BigDecimal
.
ZERO
;
try
{
if
(
StringUtils
.
isNotEmpty
(
data
.
getUnit_price
()))
{
unitPrice
=
new
BigDecimal
(
data
.
getUnit_price
().
trim
());
}
}
catch
(
Exception
e
)
{
log
.
warn
(
"单价格式转换失败: {}"
,
data
.
getUnit_price
());
unitPrice
=
BigDecimal
.
ZERO
;
}
detail
.
put
(
"unit_price"
,
unitPrice
);
// 计算总金额
BigDecimal
totalAmount
=
inboundQuantity
.
multiply
(
unitPrice
);
detail
.
put
(
"total_amount"
,
totalAmount
);
// 处理生产日期
Date
productionDate
=
null
;
if
(
StringUtils
.
isNotEmpty
(
data
.
getProduction_date
()))
{
try
{
productionDate
=
dateFormat
.
parse
(
data
.
getProduction_date
().
trim
());
}
catch
(
ParseException
e
)
{
log
.
warn
(
"生产日期格式解析失败: {}"
,
data
.
getProduction_date
());
}
}
detail
.
put
(
"production_date"
,
productionDate
);
// 处理有效期
Date
expiryDate
=
null
;
if
(
StringUtils
.
isNotEmpty
(
data
.
getExpiry_date
()))
{
try
{
expiryDate
=
dateFormat
.
parse
(
data
.
getExpiry_date
().
trim
());
}
catch
(
ParseException
e
)
{
log
.
warn
(
"有效期格式解析失败: {}"
,
data
.
getExpiry_date
());
}
}
detail
.
put
(
"expiry_date"
,
expiryDate
);
detail
.
put
(
"create_by"
,
user
.
get
(
"id"
));
detail
.
put
(
"create_time"
,
new
Date
());
detail
.
put
(
"_user"
,
user
);
return
detail
;
}
catch
(
Exception
e
)
{
log
.
error
(
"创建入库明细异常"
,
e
);
return
null
;
}
}
/**
* 插入入库单主表
*/
private
String
insertInboundMaster
(
Map
<
String
,
Object
>
inboundMaster
)
{
try
{
commonService
.
insert
(
namespace
+
"insertInboundMaster"
,
inboundMaster
);
return
(
String
)
inboundMaster
.
get
(
"id"
);
}
catch
(
Exception
e
)
{
log
.
error
(
"插入入库单主表异常"
,
e
);
return
null
;
}
}
/**
* 插入入库明细
*/
private
void
insertInboundDetail
(
Map
<
String
,
Object
>
inboundDetail
)
{
try
{
commonService
.
insert
(
namespace
+
"insertInboundDetail"
,
inboundDetail
);
}
catch
(
Exception
e
)
{
log
.
error
(
"插入入库明细异常"
,
e
);
throw
e
;
}
}
/**
* 数据校验方法
*/
private
boolean
isValidInbound
(
InboundImp
data
)
{
// 必需字段校验
if
(
StringUtils
.
isEmpty
(
data
.
getInbound_no
())
||
StringUtils
.
isEmpty
(
data
.
getMaterial_code
())
||
StringUtils
.
isEmpty
(
data
.
getInbound_quantity
()))
{
return
false
;
}
// 数量校验
try
{
BigDecimal
quantity
=
new
BigDecimal
(
data
.
getInbound_quantity
().
trim
());
if
(
quantity
.
compareTo
(
BigDecimal
.
ZERO
)
<=
0
)
{
return
false
;
}
}
catch
(
Exception
e
)
{
return
false
;
}
// 单价校验(可选)
if
(
StringUtils
.
isNotEmpty
(
data
.
getUnit_price
()))
{
try
{
new
BigDecimal
(
data
.
getUnit_price
().
trim
());
}
catch
(
Exception
e
)
{
return
false
;
}
}
return
true
;
}
public
Map
<
String
,
Object
>
getResult
()
{
Map
<
String
,
Object
>
r
=
new
HashMap
<>();
r
.
put
(
"insert"
,
insertCount
.
get
());
// 明细条数
r
.
put
(
"inbound_count"
,
inboundCount
.
get
());
// 入库单数量
r
.
put
(
"error"
,
errorCount
.
get
());
r
.
put
(
"errInfo"
,
errInfo
.
size
()
>
0
?
String
.
join
(
", "
,
errInfo
)
:
"无"
);
return
r
;
}
// 批量保存方法(如果需要保留原来的逻辑)
private
void
saveBatch
()
{
// 这里可以根据需要保留原有的批量处理逻辑
}
}
\ No newline at end of file
src/main/resources/KeyInboundImp.xlsx
0 → 100644
View file @
96e321fd
File added
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论