Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
M
mini-wms
概览
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
周海峰
mini-wms
Commits
db0c0a3a
Commit
db0c0a3a
authored
Dec 15, 2025
by
wangchunyang
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://code.palacesun.com/zhouhaifeng/mini-wms
parents
6eab21f8
7555bfca
隐藏空白字符变更
内嵌
并排
正在显示
37 个修改的文件
包含
1822 行增加
和
1573 行删除
+1822
-1573
ruoyi-admin-vue/src/components/ImportExcel/index.vue
+1
-1
ruoyi-admin-vue/src/components/rukuRankChart.vue
+3
-2
ruoyi-admin-vue/src/views/index.vue
+6
-6
ruoyi-admin-vue/src/views/inventory/inbound/index.vue
+12
-3
ruoyi-admin-vue/src/views/inventory/items/index.vue
+7
-8
ruoyi-admin-vue/src/views/inventory/materials/index.vue
+6
-1
ruoyi-admin-vue/src/views/inventory/materials/materialsSeletor.vue
+1
-1
ruoyi-admin-vue/src/views/inventory/orders/OutboundOrderFormWithItems.vue
+43
-54
ruoyi-admin-vue/src/views/inventory/orders/index.vue
+326
-357
ruoyi-admin-vue/src/views/inventory/report_view/inventory_detail.vue
+32
-2
ruoyi-admin-vue/src/views/inventory/warehouses/index.vue
+1
-8
ruoyi-admin/src/main/java/com/ruoyi/web/controller/inventory/InboundOrdersController.java
+129
-48
ruoyi-common/src/main/java/com/ruoyi/common/config/WarehouseConfig.java
+13
-0
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Materials.java
+231
-210
ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
+2
-0
ruoyi-inventory/src/main/java/com/ruoyi/inventory/controller/OutboundOrderItemsController.java
+1
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/controller/OutboundOrdersController.java
+1
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/InventoryTransactions.java
+4
-213
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/OutboundOrderItems.java
+4
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/Owners.java
+1
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/InboundTemplateVO.java
+0
-395
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/inboundVO/InboundFinishTemplateVO.java
+139
-0
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/inboundVO/InboundTRDCTemplateVO.java
+136
-0
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/inboundVO/InboundTemplateVO.java
+143
-0
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/InventoryMapper.java
+2
-0
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/IInboundOrdersService.java
+2
-3
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/IOutboundOrderItemsService.java
+0
-3
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/InboundOrdersServiceImpl.java
+153
-46
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/InventoryServiceImpl.java
+5
-6
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrderItemsServiceImpl.java
+1
-1
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrdersServiceImpl.java
+337
-168
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/StorageLocationsServiceImpl.java
+16
-9
ruoyi-inventory/src/main/resources/mapper/inventory/InboundOrdersMapper.xml
+30
-22
ruoyi-inventory/src/main/resources/mapper/inventory/InventoryMapper.xml
+8
-0
ruoyi-inventory/src/main/resources/mapper/inventory/InventoryTransactionsMapper.xml
+3
-1
ruoyi-inventory/src/main/resources/mapper/inventory/MaterialsMapper.xml
+5
-1
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrdersMapper.xml
+18
-0
没有找到文件。
ruoyi-admin-vue/src/components/ImportExcel/index.vue
View file @
db0c0a3a
...
...
@@ -151,7 +151,7 @@ export default {
},
/** 下载模板操作 */
importTemplate
()
{
this
.
download
(
this
.
templateUrl
,
{},
`
${
this
.
templateName
}
_
${
new
Date
().
getTime
()}
.xlsx`
)
this
.
download
(
this
.
templateUrl
,
{
orderType
:
this
.
upload
.
orderType
},
`
${
this
.
templateName
}
_
${
new
Date
().
getTime
()}
.xlsx`
)
},
// 文件上传中处理
handleFileUploadProgress
(
event
,
file
,
fileList
)
{
...
...
ruoyi-admin-vue/src/components/rukuRankChart.vue
View file @
db0c0a3a
...
...
@@ -94,6 +94,7 @@ export default {
grid
:
{
left
:
'3%'
,
right
:
'4%'
,
top
:
'3%'
,
bottom
:
'3%'
,
containLabel
:
true
},
...
...
@@ -130,12 +131,12 @@ export default {
series
:
[{
name
:
'标准化'
,
type
:
'bar'
,
barWidth
:
16
,
// 柱子宽度
barWidth
:
'15'
,
// 柱子宽度
label
:
{
show
:
true
,
position
:
'right'
,
// 位置
color
:
'rgba(102, 102, 102, 1)'
,
fontSize
:
1
4
,
fontSize
:
1
2
,
fontWeight
:
'bold'
,
// 加粗
distance
:
5
// 距离
},
// 柱子上方的数值
...
...
ruoyi-admin-vue/src/views/index.vue
View file @
db0c0a3a
...
...
@@ -63,7 +63,7 @@
<div
class=
"card-container-flex chart-container shadow flex1"
>
<div
class=
"tip-title"
>
<div
class=
"title-text"
>
本月入库排名前
10
物料
</div>
<div
class=
"title-text"
>
本月入库排名前
5
物料
</div>
<el-radio-group
v-model=
"rukuRankType"
size=
"mini"
@
change=
"rukuRankTypeChange"
>
<el-radio-button
label=
"count"
>
按数量
</el-radio-button>
<el-radio-button
label=
"money"
>
按金额
</el-radio-button>
...
...
@@ -75,7 +75,7 @@
</div>
<div
class=
"card-container-flex chart-container shadow flex1 two"
>
<div
class=
"tip-title"
>
<div
class=
"title-text"
>
本月出库排名前
10
物料
</div>
<div
class=
"title-text"
>
本月出库排名前
5
物料
</div>
<el-radio-group
v-model=
"cukuRankType"
size=
"mini"
@
change=
"cukuRankTypeChange"
>
<el-radio-button
label=
"count"
>
按数量
</el-radio-button>
<el-radio-button
label=
"money"
>
按金额
</el-radio-button>
...
...
@@ -186,7 +186,7 @@ export default {
this
.
rukuList
=
data
.
map
(
item
=>
({
value
:
item
.
totalQuantity
,
name
:
item
.
materialName
}))
}))
.
splice
(
0
,
5
).
reverse
()
})
}
if
(
this
.
rukuRankType
===
'money'
){
...
...
@@ -196,7 +196,7 @@ export default {
this
.
rukuList
=
data
.
map
(
item
=>
({
value
:
item
.
totalMoney
,
name
:
item
.
materialName
}))
}))
.
splice
(
0
,
5
).
reverse
()
})
}
},
...
...
@@ -234,14 +234,14 @@ export default {
outboundOrdersTopTenByQuantity
().
then
(
res
=>
{
let
data
=
res
.
rows
if
(
!
data
)
return
this
.
cukuList
=
data
this
.
cukuList
=
data
.
splice
(
0
,
5
).
reverse
()
})
}
if
(
this
.
cukuRankType
===
'money'
){
outboundOrdersTopTenByAmount
().
then
(
res
=>
{
let
data
=
res
.
rows
if
(
!
data
)
return
this
.
cukuList
=
data
this
.
cukuList
=
data
.
splice
(
0
,
5
).
reverse
()
})
}
}
...
...
ruoyi-admin-vue/src/views/inventory/inbound/index.vue
View file @
db0c0a3a
...
...
@@ -443,7 +443,7 @@
title
=
"导入"
import
-
url
=
"/inventory/inbound/import"
template
-
url
=
"/inventory/inbound/importTemplate"
template
-
name
=
"入库单导入模板
"
:
template
-
name
=
"getTemplateName()
"
@
success
=
"getList"
:
show
-
trdc
-
checkbox
=
"true"
@
orderTypeChange
=
"handleOrderTypeChange"
...
...
@@ -703,14 +703,14 @@ export default {
/** 修改按钮操作 */
handleUpdate
(
row
)
{
this
.
reset
();
let
id
=
row
.
id
;
if
(
id
===
undefined
){
id
=
this
.
ids
[
0
]
}
getInbound
(
id
).
then
(
response
=>
{
if
(
response
.
data
.
orderStatus
===
2
){
this
.
$modal
.
msgWarning
(
"该入库单已提交,不能修改"
);
this
.
$modal
.
msgWarning
(
"该入库单已提交,不能修改"
);
return
;
}
this
.
form
=
response
.
data
||
{
}
;
...
...
@@ -1051,6 +1051,15 @@ export default {
handleImport() {
this.$refs.import.show()
}
,
getTemplateName(){
if(this.form.orderTypeId === '1'){
return "入库单导入模板"
}
else if(this.form.orderTypeId === '2'){
return "成品入库单导入模板"
}
else if(this.form.orderTypeId === '3'){
return "退料TRDC入库单导入模板"
}
}
,
/** 处理明细项选择变化 */
handleItemsSelectionChange(selection) {
this.selectedItems = selection
...
...
ruoyi-admin-vue/src/views/inventory/items/index.vue
View file @
db0c0a3a
...
...
@@ -16,16 +16,15 @@
<!-- 页面容器 -->
<div
class=
"page-container"
>
<!-- 物料查询表单 -->
<el-form
:model=
"queryParams"
ref=
"queryForm"
size=
"small"
:inline=
"true"
v-show=
"showSearch"
label-width=
"100px"
>
<
el-form-item
label=
"主订单号"
prop=
"mainO
rderId"
>
<
!-- <el-form-item label="主订单号" prop="o
rderId">
<el-input
v-model=
"queryParams.
mainO
rderId"
v-model="queryParams.
o
rderId"
placeholder="请输入主订单号"
clearable
@keyup.enter.native="handleQuery"
/>
</el-form-item>
</el-form-item>
-->
<el-form-item
label=
"时间段"
prop=
"dateRange"
>
<el-date-picker
v-model=
"queryParams.dateRange"
...
...
@@ -253,7 +252,7 @@
style=
"width: 100%"
>
<el-table-column
type=
"index"
label=
"序号"
width=
"60"
align=
"center"
/>
<el-table-column
label=
"主订单号"
align=
"center"
prop=
"
mainO
rderId"
width=
"150"
/>
<el-table-column
label=
"主订单号"
align=
"center"
prop=
"
o
rderId"
width=
"150"
/>
<el-table-column
label=
"物料名称"
align=
"center"
prop=
"materialName"
min-width=
"150"
show-overflow-tooltip
/>
<el-table-column
label=
"批次"
align=
"center"
prop=
"batchCode"
width=
"120"
/>
<el-table-column
label=
"仓库"
align=
"center"
prop=
"warehouseName"
width=
"120"
/>
...
...
@@ -314,7 +313,7 @@ export default {
queryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
mainO
rderId
:
null
,
o
rderId
:
null
,
startDate
:
null
,
endDate
:
null
,
ownerId
:
null
,
...
...
@@ -339,7 +338,7 @@ export default {
detailQueryParams
:
{
pageNum
:
1
,
pageSize
:
10
,
mainO
rderId
:
null
,
o
rderId
:
null
,
materialId
:
null
,
warehouseId
:
null
,
warehousesCode
:
null
,
...
...
@@ -466,7 +465,7 @@ export default {
this
.
detailQueryParams
=
{
pageNum
:
1
,
pageSize
:
10
,
mainOrderId
:
row
.
mainO
rderId
,
orderId
:
row
.
o
rderId
,
materialId
:
row
.
materialId
,
warehouseId
:
null
,
warehousesCode
:
null
,
...
...
ruoyi-admin-vue/src/views/inventory/materials/index.vue
View file @
db0c0a3a
...
...
@@ -144,6 +144,7 @@
<el-table-column
label=
"SAP物料号"
align=
"center"
prop=
"sapNo"
width=
"150"
/>
<!-- <el-table-column label="物料编码" align="center" prop="materialCode" width="120"/> -->
<el-table-column
label=
"物料名称"
align=
"center"
prop=
"materialName"
width=
"150"
/>
<el-table-column
label=
"物料英文名称"
align=
"center"
prop=
"materialEname"
width=
"150"
/>
<el-table-column
label=
"TS Code"
align=
"center"
prop=
"tsCode"
width=
"150"
/>
<el-table-column
label=
"物料分类"
align=
"center"
prop=
"categoryCode"
>
<
template
slot-scope=
"scope"
>
...
...
@@ -298,6 +299,9 @@
<el-form-item
label=
"物料名称"
prop=
"materialName"
>
<el-input
v-model=
"form.materialName"
placeholder=
"请输入物料名称"
/>
</el-form-item>
<el-form-item
label=
"物料英文名称"
prop=
"materialEname"
>
<el-input
v-model=
"form.materialEname"
placeholder=
"请输入物料英文名称"
/>
</el-form-item>
<el-form-item
label=
"物料分类"
prop=
"categoryCode"
>
<el-select
v-model=
"form.categoryCode"
placeholder=
"请选择物料分类"
clearable
>
<el-option
...
...
@@ -444,6 +448,7 @@ export default {
id
:
null
,
materialCode
:
null
,
materialName
:
null
,
materialEname
:
null
,
sapNo
:
null
,
tsCode
:
null
,
categoryCode
:
null
,
...
...
@@ -654,7 +659,7 @@ export default {
.
map
(
item
=>
({
...
item
,
// 兜底:如果映射表中没有,显示原始code并标注
displayCategory
:
this
.
categoryMap
[
item
.
categoryCode
]
||
`
${
item
.
categoryCode
}
(未匹配分类)
`
displayCategory
:
this
.
categoryMap
[
item
.
categoryCode
]
||
`
未匹配分类
`
}));
this
.
total
=
total
;
}
catch
(
error
)
{
...
...
ruoyi-admin-vue/src/views/inventory/materials/materialsSeletor.vue
View file @
db0c0a3a
...
...
@@ -251,7 +251,7 @@ export default {
.
filter
(
item
=>
item
.
isUsed
!==
0
&&
item
.
isUsed
!==
'0'
)
.
map
(
item
=>
({
...
item
,
displayCategory
:
this
.
categoryMap
[
item
.
categoryCode
]
||
`
${
item
.
categoryCode
}
(未匹配分类)
`
displayCategory
:
this
.
categoryMap
[
item
.
categoryCode
]
||
`
未匹配分类
`
}));
this
.
total
=
response
.
total
;
}).
finally
(()
=>
{
...
...
ruoyi-admin-vue/src/views/inventory/orders/OutboundOrderFormWithItems.vue
View file @
db0c0a3a
...
...
@@ -121,6 +121,41 @@
</div>
<el-row
:gutter=
"20"
>
<el-col
:span=
"8"
>
<el-form-item
label=
"计划数量"
prop=
"plannedQuantity"
required
>
<el-input
v-model
.
number=
"currentSelectedRow.plannedQuantity"
type=
"number"
min=
"1"
:max=
"(currentSelectedRow.quantity || 0) - (currentSelectedRow.lockedQuantity || 0)"
@
input=
"handleRowPlannedQtyInput(currentSelectedRow); syncDetails(false)"
placeholder=
"输入计划数量"
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
label=
"单价"
prop=
"unitPrice"
required
>
<el-input
v-model
.
number=
"currentSelectedRow.unitPrice"
placeholder=
"请输入单价"
type=
"number"
min=
"0"
step=
"0.01"
@
input=
"syncDetails(false)"
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
label=
"凭证号"
prop=
"voucherNumber"
>
<el-input
v-model=
"currentSelectedRow.voucherNumber"
placeholder=
"请输入凭证号"
@
input=
"syncDetails(false)"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"20"
style=
"margin-top: 10px;"
>
<el-col
:span=
"8"
>
<el-form-item
label=
"约数"
prop=
"divisor"
>
<el-input
v-model
.
number=
"currentSelectedRow.divisor"
...
...
@@ -148,32 +183,6 @@
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
label=
"计划数量"
prop=
"plannedQuantity"
>
<el-input
v-model
.
number=
"currentSelectedRow.plannedQuantity"
type=
"number"
min=
"1"
:max=
"(currentSelectedRow.quantity || 0) - (currentSelectedRow.lockedQuantity || 0)"
@
input=
"handleRowPlannedQtyInput(currentSelectedRow); syncDetails(false)"
placeholder=
"输入计划数量"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"20"
style=
"margin-top: 10px;"
>
<el-col
:span=
"8"
>
<el-form-item
label=
"单价"
prop=
"unitPrice"
>
<el-input
v-model
.
number=
"currentSelectedRow.unitPrice"
placeholder=
"请输入单价"
type=
"number"
min=
"0"
step=
"0.01"
@
input=
"syncDetails(false)"
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
label=
"发货方"
prop=
"shippedBy"
>
<el-input
v-model=
"currentSelectedRow.shippedBy"
...
...
@@ -182,16 +191,8 @@
/>
</el-form-item>
</el-col>
<el-col
:span=
"8"
>
<el-form-item
label=
"凭证号"
prop=
"voucherNumber"
>
<el-input
v-model=
"currentSelectedRow.voucherNumber"
placeholder=
"请输入凭证号"
@
input=
"syncDetails(false)"
/>
</el-form-item>
</el-col>
</el-row>
<el-row
:gutter=
"20"
style=
"margin-top: 10px;"
>
<el-col
:span=
"16"
>
<el-form-item
label=
"备注"
prop=
"remark"
>
...
...
@@ -226,6 +227,7 @@
<el-table-column
prop=
"batchId"
label=
"批次ID"
width=
"150"
/>
<el-table-column
prop=
"warehousesName"
label=
"仓库名称"
width=
"120"
/>
<el-table-column
prop=
"locationName"
label=
"库位名称"
width=
"120"
/>
<el-table-column
prop=
"plannedQuantity"
label=
"计划数量"
width=
"100"
/>
<el-table-column
prop=
"actualQuantity"
label=
"实际数量"
width=
"100"
fixed=
"right"
/>
<el-table-column
prop=
"unitPrice"
label=
"单价"
width=
"100"
/>
...
...
@@ -637,31 +639,18 @@ syncDetails(strict = true) {
if
(
row
.
plannedQuantity
>
availableQty
)
{
rowErrors
.
push
(
`计划数量不能超过可用库存(
${
availableQty
}
)`
);
}
}
else
{
rowErrors
.
push
(
`请填写计划数量`
);
}
// 3. 除数(有值才校验,无值不提示)
if
(
row
.
divisor
!==
null
&&
row
.
divisor
!==
undefined
)
{
if
(
row
.
unitPrice
!==
null
&&
row
.
unitPrice
!==
undefined
)
{
// 若有值但为0/负数,可补充校验(按需)
if
(
row
.
divisor
<=
0
)
{
rowErrors
.
push
(
'
换算率(除数)必须大于0
'
);
if
(
row
.
unitPrice
<=
0
)
{
rowErrors
.
push
(
'
请填写单价
'
);
}
}
// 4. 标签颜色(有值才校验,空字符串算不合规)
if
(
row
.
labelColor
!==
undefined
&&
row
.
labelColor
===
''
)
{
rowErrors
.
push
(
'请填写标签颜色'
);
}
// 5. 凭证号(有值才校验,空字符串算不合规)
if
(
row
.
voucherNumber
!==
undefined
&&
row
.
voucherNumber
===
''
)
{
rowErrors
.
push
(
'请填写凭证号'
);
}
// 6. 发货人(有值才校验,空字符串算不合规)
if
(
row
.
shippedBy
!==
undefined
&&
row
.
shippedBy
===
''
)
{
rowErrors
.
push
(
'请填写发货人'
);
}
// 收集当前行的错误(仅有值但不合规的字段)
if
(
rowErrors
.
length
>
0
)
{
errorMessages
.
push
(
`
${
rowName
}
:
${
rowErrors
.
join
(
'、'
)}
`
);
...
...
ruoyi-admin-vue/src/views/inventory/orders/index.vue
View file @
db0c0a3a
...
...
@@ -125,6 +125,16 @@
</
template
>
</el-input>
</el-form-item>
<el-form-item
label=
"出库日期"
prop=
"inboundDate"
>
<el-date-picker
clearable
v-model=
"queryParams.inboundDate"
type=
"date"
value-format=
"yyyy-MM-dd"
placeholder=
"请选择出库日期"
style=
"width: 100%"
/>
</el-form-item>
<el-form-item
label=
"订单状态"
prop=
"orderStatus"
>
<el-select
v-model=
"queryParams.orderStatus"
...
...
@@ -140,16 +150,6 @@
/>
</el-select>
</el-form-item>
<el-form-item
label=
"出库日期"
prop=
"inboundDate"
>
<el-date-picker
clearable
v-model=
"queryParams.inboundDate"
type=
"date"
value-format=
"yyyy-MM-dd"
placeholder=
"请选择出库日期"
style=
"width: 100%"
/>
</el-form-item>
<el-form-item
label=
"目的地"
prop=
"destination"
>
<el-input
v-model=
"queryParams.destination"
...
...
@@ -255,6 +255,7 @@
v
-
if
=
"scope.row.orderStatus===1"
@
click
=
"handleShip(scope.row)"
v
-
hasPermi
=
"['inventory:orders:edit']"
:
loading
=
"shipLoading[scope.row.id]"
>
出货
<
/el-button
>
<
el
-
button
size
=
"mini"
...
...
@@ -310,28 +311,7 @@
<
/el-form-item
>
<
/el-col
>
<!--
新增:订单类型表单项
-->
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"订单类型"
prop
=
"orderType"
>
<
el
-
select
v
-
model
=
"form.orderType"
placeholder
=
"请选择订单类型"
:
disabled
=
"isViewDetail || formDisabled.orderType"
style
=
"width: 100%"
>
<
el
-
option
v
-
for
=
"item in dict.type.order_type"
:
key
=
"item.value"
:
label
=
"item.label"
:
value
=
"item.value"
>
<
span
style
=
"margin-left: 8px;"
>
{{
item
.
label
}}
<
/span
>
<
/el-option
>
<
/el-select
>
<
/el-form-item
>
<
/el-col
>
<
/el-row
>
<
el
-
row
:
gutter
=
"20"
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"批次ID"
prop
=
"batchCode"
>
<
el
-
input
v
-
model
=
"form.batchCode"
placeholder
=
"请输入批次ID"
:
disabled
=
"isViewDetail || formDisabled.batchCode"
/>
<
/el-form-item
>
<
/el-col
>
<
el
-
col
:
span
=
"12"
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"仓库"
prop
=
"warehouseId"
>
<
el
-
input
v
-
model
=
"form.warehouseName"
...
...
@@ -356,6 +336,26 @@
<
/el-row
>
<
el
-
row
:
gutter
=
"20"
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"批次ID"
prop
=
"batchCode"
>
<
el
-
input
v
-
model
=
"form.batchCode"
placeholder
=
"请输入批次ID"
:
disabled
=
"isViewDetail || formDisabled.batchCode"
/>
<
/el-form-item
>
<
/el-col
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"出库日期"
prop
=
"inboundDate"
>
<
el
-
date
-
picker
clearable
v
-
model
=
"form.inboundDate"
type
=
"date"
value
-
format
=
"yyyy-MM-dd"
placeholder
=
"请选择出库日期"
:
disabled
=
"isViewDetail"
style
=
"width: 100%"
/>
<
/el-form-item
>
<
/el-col
>
<
/el-row
>
<
el
-
row
:
gutter
=
"20"
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"货主"
prop
=
"ownerId"
>
<
el
-
input
v
-
model
=
"form.ownerName"
...
...
@@ -377,19 +377,22 @@
<
/el-input
>
<
/el-form-item
>
<
/el-col
>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"出库日期"
prop
=
"inboundDate"
>
<
el
-
date
-
picker
clearable
v
-
model
=
"form.inboundDate"
type
=
"date"
value
-
format
=
"yyyy-MM-dd"
placeholder
=
"请选择出库日期"
:
disabled
=
"isViewDetail"
style
=
"width: 100%"
/>
<
el
-
col
:
span
=
"12"
>
<
el
-
form
-
item
label
=
"订单类型"
prop
=
"orderType"
>
<
el
-
select
v
-
model
=
"form.orderType"
placeholder
=
"请选择订单类型"
:
disabled
=
"isViewDetail || formDisabled.orderType"
style
=
"width: 100%"
>
<
el
-
option
v
-
for
=
"item in dict.type.order_type"
:
key
=
"item.value"
:
label
=
"item.label"
:
value
=
"item.value"
>
<
span
style
=
"margin-left: 8px;"
>
{{
item
.
label
}}
<
/span
>
<
/el-option
>
<
/el-select
>
<
/el-form-item
>
<
/el-col
>
<
/el-row
>
<
el
-
row
:
gutter
=
"20"
>
<
el
-
col
:
span
=
"12"
>
...
...
@@ -514,20 +517,19 @@
@
selected
=
"handleLocationSelected"
/>
<
import
-
excel
ref
=
"import"
title
=
"导入"
import
-
url
=
"/inventory/orders/import"
template
-
url
=
"/inventory/orders/importTemplate"
template
-
name
=
"出库单导入模板"
@
success
=
"getList"
:
show
-
trdc
-
checkbox
=
"true"
@
orderTypeChange
=
"handleOrderTypeChange"
:
orderTypeRequired
=
"true"
/>
<
import
-
excel
ref
=
"import"
title
=
"导入"
import
-
url
=
"/inventory/orders/import"
template
-
url
=
"/inventory/orders/importTemplate"
template
-
name
=
"出库单导入模板"
@
success
=
"getList"
:
show
-
trdc
-
checkbox
=
"true"
@
orderTypeChange
=
"handleOrderTypeChange"
:
orderTypeRequired
=
"true"
/>
<
/div
>
<
/template
>
<
script
>
import
{
listOrders
,
getOrders
,
delOrders
,
addOrders
,
updateOrders
,
ship
}
from
"@/api/inventory/orders"
import
{
getMaterialsdicts
}
from
"@/api/inventory/materials"
...
...
@@ -557,6 +559,8 @@ export default {
tableKey
:
1
,
// 遮罩层
loading
:
true
,
// 出货loading(按订单ID存储,支持多订单同时操作)
shipLoading
:
{
}
,
// 新增:出货loading状态
// 选中数组
ids
:
[],
// 非单个禁用
...
...
@@ -657,9 +661,9 @@ export default {
rules
:
{
orderId
:
[{
required
:
true
,
message
:
'请输入出库单号'
,
trigger
:
'blur'
}
],
warehouseId
:
[{
required
:
true
,
message
:
'请选择仓库'
,
trigger
:
'blur'
}
],
ownerId
:
[{
required
:
true
,
message
:
'请选择货主'
,
trigger
:
'blur'
}
],
inboundDate
:
[{
required
:
true
,
message
:
'请选择出库日期'
,
trigger
:
'change'
}
],
orderType
:
[{
required
:
true
,
message
:
'请选择订单类型'
,
trigger
:
'change'
}
],
// 新增:订单类型校验
orderTypeId
:
[{
required
:
true
,
message
:
'请选择出库类型'
,
trigger
:
'change'
}
],
batchCode
:
[{
required
:
true
,
message
:
'请选输入批次号'
,
trigger
:
'change'
}
],
}
,
// 货主/仓库选择相关
ownerSelectorVisible
:
false
,
...
...
@@ -678,13 +682,29 @@ export default {
this
.
$nextTick
(()
=>
{
this
.
getList
()
}
)
this
.
handleShip
=
this
.
debounce
(
this
.
handleShip
,
500
)
}
,
methods
:
{
handleOrderTypeChange
(
selection
)
{
debounce
(
fn
,
delay
=
300
)
{
let
timer
=
null
;
let
pendingPromise
=
null
;
return
async
function
(...
args
)
{
if
(
timer
)
clearTimeout
(
timer
);
pendingPromise
=
new
Promise
((
resolve
)
=>
{
timer
=
setTimeout
(
async
()
=>
{
const
result
=
await
fn
.
apply
(
this
,
args
);
resolve
(
result
);
timer
=
null
;
}
,
delay
);
}
);
return
pendingPromise
;
}
;
}
,
handleOrderTypeChange
(
selection
)
{
this
.
form
.
orderTypeId
=
selection
}
,
/** 打开导入弹窗 */
/** 打开导入弹窗 */
handleImport
()
{
this
.
$refs
.
import
.
show
()
}
,
...
...
@@ -722,24 +742,24 @@ export default {
this
.
ownerSelectorVisible
=
true
}
,
// 货主选择回调(核心缺失方法)
handleOwnerSelected
(
owner
)
{
if
(
!
owner
)
return
if
(
this
.
ownerSelectTarget
===
'query'
)
{
this
.
queryParams
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
queryOwnerName
=
owner
.
ownerName
||
owner
.
name
this
.
handleQuery
()
}
else
{
this
.
form
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
form
.
ownerName
=
owner
.
ownerName
||
owner
.
name
// 更新明细中的默认货主(可选)
if
(
this
.
currentDetailItem
)
{
this
.
currentDetailItem
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
currentDetailItem
.
ownerName
=
owner
.
ownerName
||
owner
.
name
}
}
this
.
ownerSelectorVisible
=
false
}
,
handleOwnerSelected
(
owner
)
{
if
(
!
owner
)
return
if
(
this
.
ownerSelectTarget
===
'query'
)
{
this
.
queryParams
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
queryOwnerName
=
owner
.
ownerName
||
owner
.
name
this
.
handleQuery
()
}
else
{
this
.
form
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
form
.
ownerName
=
owner
.
ownerName
||
owner
.
name
// 更新明细中的默认货主(可选)
if
(
this
.
currentDetailItem
)
{
this
.
currentDetailItem
.
ownerId
=
owner
.
ownerId
||
owner
.
id
this
.
currentDetailItem
.
ownerName
=
owner
.
ownerName
||
owner
.
name
}
}
this
.
ownerSelectorVisible
=
false
}
,
// 打开仓库选择器
openWarehouseSelector
(
target
=
'form'
)
{
this
.
warehouseSelectTarget
=
target
...
...
@@ -796,26 +816,35 @@ handleOwnerSelected(owner) {
calcGroupAmount
(
items
)
{
return
items
.
reduce
((
sum
,
item
)
=>
sum
+
(
Number
(
item
.
amount
)
||
0
),
0
).
toFixed
(
2
)
}
,
// 核心出货方法
// 核心出货方法
(添加loading+弹窗确认)
async
handleShip
(
row
)
{
try
{
// 调用ship接口提交数据到后端
console
.
log
(
"handleShip"
,
row
)
await
ship
({
...
row
,
orderId
:
row
.
orderId
,
// 用户填写的出货单号
outboundOrderId
:
row
.
id
// 主表ID作为outboundOrderId
}
)
// 提示成功并刷新列表
this
.
$modal
.
msgSuccess
(
"出货操作成功,数据已提交到后端"
)
this
.
getList
()
}
catch
(
error
)
{
// 错误处理
this
.
$modal
.
msgError
(
error
.
msg
||
"出货操作失败"
)
}
}
,
// 修复:获取要传递给子组件的初始化明细数据(按物料分组)
// 新增:出货前弹窗确认
this
.
$modal
.
confirm
(
`是否确认对出库单【${row.orderId
}
】执行出货操作?`
).
then
(
async
()
=>
{
try
{
// 设置当前订单出货loading
this
.
$set
(
this
.
shipLoading
,
row
.
id
,
true
)
// 原有业务逻辑
console
.
log
(
"handleShip"
,
row
)
await
ship
({
...
row
,
orderId
:
row
.
orderId
,
// 用户填写的出货单号
outboundOrderId
:
row
.
id
// 主表ID作为outboundOrderId
}
)
// 提示成功并刷新列表
this
.
$modal
.
msgSuccess
(
"出货操作成功,数据已提交到后端"
)
this
.
getList
()
}
catch
(
error
)
{
// 错误处理
this
.
$modal
.
msgError
(
error
.
msg
||
"出货操作失败"
)
}
finally
{
// 关闭loading
this
.
$delete
(
this
.
shipLoading
,
row
.
id
)
}
}
).
catch
(()
=>
{
// 取消确认时不执行任何操作
}
)
}
,
// 修复:获取要传递给子组件的初始化明细数据(按物料分组)
getInitDetails
()
{
// 编辑场景:传递当前物料分组的所有明细(确保子组件反显)
if
(
this
.
isEditDetail
&&
this
.
currentMaterialId
)
{
...
...
@@ -941,116 +970,116 @@ handleOwnerSelected(owner) {
this
.
detailDialogOpen
=
true
}
)
}
,
handleDetailSubmit
(
details
)
{
// 确保是数组格式
const
detailList
=
Array
.
isArray
(
details
)
?
details
:
[
details
];
if
(
detailList
.
length
===
0
)
{
this
.
$message
.
warning
(
"请填写明细数据"
);
return
;
}
const
materialId
=
this
.
currentMaterialId
||
detailList
[
0
]?.
materialId
;
if
(
!
materialId
)
{
this
.
$message
.
warning
(
"物料ID不能为空"
);
return
;
}
// 初始化物料分组
if
(
!
this
.
outboundOrderItemsGroup
[
materialId
])
{
this
.
outboundOrderItemsGroup
[
materialId
]
=
{
materialId
:
materialId
,
materialName
:
detailList
[
0
]?.
materialName
||
''
,
// 【修改9】初始化分组的物料名称
items
:
[]
}
;
}
const
group
=
this
.
outboundOrderItemsGroup
[
materialId
];
handleDetailSubmit
(
details
)
{
// 确保是数组格式
const
detailList
=
Array
.
isArray
(
details
)
?
details
:
[
details
];
if
(
detailList
.
length
===
0
)
{
this
.
$message
.
warning
(
"请填写明细数据"
);
return
;
}
if
(
this
.
isEditDetail
)
{
// 修复:编辑模式 - 全量替换分组数据(而非追加)
const
newDetails
=
detailList
.
map
((
item
,
idx
)
=>
{
const
amount
=
(
Number
(
item
.
actualQuantity
)
||
0
)
*
(
Number
(
item
.
unitPrice
)
||
0
);
return
{
...
item
,
index
:
idx
+
1
,
orderId
:
null
,
// 明细的orderId设为空
outboundOrderId
:
this
.
form
.
id
,
// 使用主表ID作为outboundOrderId
materialId
:
materialId
,
materialName
:
item
.
materialName
||
group
.
materialName
||
''
,
// 【修改10】保留物料名称
inventoryId
:
item
.
inventoryId
||
''
,
itemStatus
:
Number
(
item
.
itemStatus
)
||
1
,
labelColor
:
Number
(
item
.
labelColor
)
||
0
,
divisor
:
Number
(
item
.
divisor
)
||
1
,
shippedAt
:
this
.
form
.
inboundDate
,
plannedQuantity
:
Number
(
item
.
plannedQuantity
)
||
0
,
actualQuantity
:
Number
(
item
.
actualQuantity
)
||
0
,
unitPrice
:
Number
(
item
.
unitPrice
)
||
0.00
,
amount
:
amount
,
isUsed
:
1
,
sortNo
:
0
,
remark
:
item
.
remark
||
''
,
warehouseName
:
item
.
warehouseName
||
this
.
form
.
warehouseName
||
''
,
locationName
:
item
.
locationName
||
''
,
batchCode
:
item
.
batchId
||
''
// 新增:将子组件的batchId赋值给batchCode
}
;
}
);
const
materialId
=
this
.
currentMaterialId
||
detailList
[
0
]?.
materialId
;
if
(
!
materialId
)
{
this
.
$message
.
warning
(
"物料ID不能为空"
);
return
;
}
// 全量替换分组数据
group
.
items
=
newDetails
;
// 更新分组的物料名称(取第一条的物料名称)
group
.
materialName
=
newDetails
[
0
]?.
materialName
||
group
.
materialName
;
this
.
$message
.
success
(
`成功编辑${materialId
}
物料组,共${newDetails.length
}
条明细`
);
}
else
{
// 新增模式:按库存ID去重后追加
const
existingInventoryIds
=
new
Set
(
group
.
items
.
map
(
item
=>
item
.
inventoryId
));
const
newDetails
=
detailList
.
filter
(
item
=>
item
.
inventoryId
&&
!
existingInventoryIds
.
has
(
item
.
inventoryId
))
.
map
((
item
,
idx
)
=>
{
const
newIndex
=
group
.
items
.
length
+
idx
+
1
;
const
amount
=
(
Number
(
item
.
actualQuantity
)
||
0
)
*
(
Number
(
item
.
unitPrice
)
||
0
);
return
{
...
item
,
index
:
newIndex
,
orderId
:
null
,
// 明细的orderId设为空
outboundOrderId
:
this
.
form
.
id
||
null
,
// 使用主表ID作为outboundOrderId
// 初始化物料分组
if
(
!
this
.
outboundOrderItemsGroup
[
materialId
])
{
this
.
outboundOrderItemsGroup
[
materialId
]
=
{
materialId
:
materialId
,
materialName
:
item
.
materialName
||
''
,
// 【修改11】保留物料名称
inventoryId
:
item
.
inventoryId
||
''
,
itemStatus
:
Number
(
item
.
itemStatus
)
||
1
,
labelColor
:
Number
(
item
.
labelColor
)
||
0
,
divisor
:
Number
(
item
.
divisor
)
||
1
,
plannedQuantity
:
Number
(
item
.
plannedQuantity
)
||
0
,
actualQuantity
:
Number
(
item
.
actualQuantity
)
||
0
,
unitPrice
:
Number
(
item
.
unitPrice
)
||
0.00
,
amount
:
amount
,
isUsed
:
1
,
sortNo
:
0
,
remark
:
item
.
remark
||
''
,
warehouseName
:
item
.
warehouseName
||
this
.
form
.
warehouseName
||
''
,
locationName
:
item
.
locationName
||
''
,
batchCode
:
item
.
batchId
||
''
// 新增:将子组件的batchId赋值给batchCode
materialName
:
detailList
[
0
]?.
materialName
||
''
,
// 【修改9】初始化分组的物料名称
items
:
[]
}
;
}
);
}
const
group
=
this
.
outboundOrderItemsGroup
[
materialId
];
if
(
newDetails
.
length
===
0
)
{
this
.
$message
.
warning
(
"该库存明细已存在,无法重复添加"
);
this
.
detailDialogOpen
=
false
;
return
;
}
if
(
this
.
isEditDetail
)
{
// 修复:编辑模式 - 全量替换分组数据(而非追加)
const
newDetails
=
detailList
.
map
((
item
,
idx
)
=>
{
const
amount
=
(
Number
(
item
.
actualQuantity
)
||
0
)
*
(
Number
(
item
.
unitPrice
)
||
0
);
return
{
...
item
,
index
:
idx
+
1
,
orderId
:
null
,
// 明细的orderId设为空
outboundOrderId
:
this
.
form
.
id
,
// 使用主表ID作为outboundOrderId
materialId
:
materialId
,
materialName
:
item
.
materialName
||
group
.
materialName
||
''
,
// 【修改10】保留物料名称
inventoryId
:
item
.
inventoryId
||
''
,
itemStatus
:
Number
(
item
.
itemStatus
)
||
1
,
labelColor
:
Number
(
item
.
labelColor
)
||
0
,
divisor
:
Number
(
item
.
divisor
)
||
1
,
shippedAt
:
this
.
form
.
inboundDate
,
plannedQuantity
:
Number
(
item
.
plannedQuantity
)
||
0
,
actualQuantity
:
Number
(
item
.
actualQuantity
)
||
0
,
unitPrice
:
Number
(
item
.
unitPrice
)
||
0.00
,
amount
:
amount
,
isUsed
:
1
,
sortNo
:
0
,
remark
:
item
.
remark
||
''
,
warehouseName
:
item
.
warehouseName
||
this
.
form
.
warehouseName
||
''
,
locationName
:
item
.
locationName
||
''
,
batchCode
:
item
.
batchId
||
''
// 新增:将子组件的batchId赋值给batchCode
}
;
}
);
group
.
items
=
[...
group
.
items
,
...
newDetails
];
// 更新分组的物料名称(如果为空,取第一条的物料名称)
if
(
!
group
.
materialName
)
{
group
.
materialName
=
newDetails
[
0
]?.
materialName
||
''
;
}
this
.
$message
.
success
(
`成功新增${newDetails.length
}
条明细`
);
}
// 全量替换分组数据
group
.
items
=
newDetails
;
// 更新分组的物料名称(取第一条的物料名称)
group
.
materialName
=
newDetails
[
0
]?.
materialName
||
group
.
materialName
;
this
.
$message
.
success
(
`成功编辑${materialId
}
物料组,共${newDetails.length
}
条明细`
);
}
else
{
// 新增模式:按库存ID去重后追加
const
existingInventoryIds
=
new
Set
(
group
.
items
.
map
(
item
=>
item
.
inventoryId
));
const
newDetails
=
detailList
.
filter
(
item
=>
item
.
inventoryId
&&
!
existingInventoryIds
.
has
(
item
.
inventoryId
))
.
map
((
item
,
idx
)
=>
{
const
newIndex
=
group
.
items
.
length
+
idx
+
1
;
const
amount
=
(
Number
(
item
.
actualQuantity
)
||
0
)
*
(
Number
(
item
.
unitPrice
)
||
0
);
return
{
...
item
,
index
:
newIndex
,
orderId
:
null
,
// 明细的orderId设为空
outboundOrderId
:
this
.
form
.
id
||
null
,
// 使用主表ID作为outboundOrderId
materialId
:
materialId
,
materialName
:
item
.
materialName
||
''
,
// 【修改11】保留物料名称
inventoryId
:
item
.
inventoryId
||
''
,
itemStatus
:
Number
(
item
.
itemStatus
)
||
1
,
labelColor
:
Number
(
item
.
labelColor
)
||
0
,
divisor
:
Number
(
item
.
divisor
)
||
1
,
plannedQuantity
:
Number
(
item
.
plannedQuantity
)
||
0
,
actualQuantity
:
Number
(
item
.
actualQuantity
)
||
0
,
unitPrice
:
Number
(
item
.
unitPrice
)
||
0.00
,
amount
:
amount
,
isUsed
:
1
,
sortNo
:
0
,
remark
:
item
.
remark
||
''
,
warehouseName
:
item
.
warehouseName
||
this
.
form
.
warehouseName
||
''
,
locationName
:
item
.
locationName
||
''
,
batchCode
:
item
.
batchId
||
''
// 新增:将子组件的batchId赋值给batchCode
}
;
}
);
// 重新计算总数和总金额
this
.
calcTotalQuantity
();
this
.
detailDialogOpen
=
false
;
// 强制更新视图
this
.
$forceUpdate
();
}
,
if
(
newDetails
.
length
===
0
)
{
this
.
$message
.
warning
(
"该库存明细已存在,无法重复添加"
);
this
.
detailDialogOpen
=
false
;
return
;
}
group
.
items
=
[...
group
.
items
,
...
newDetails
];
// 更新分组的物料名称(如果为空,取第一条的物料名称)
if
(
!
group
.
materialName
)
{
group
.
materialName
=
newDetails
[
0
]?.
materialName
||
''
;
}
this
.
$message
.
success
(
`成功新增${newDetails.length
}
条明细`
);
}
// 重新计算总数和总金额
this
.
calcTotalQuantity
();
this
.
detailDialogOpen
=
false
;
// 强制更新视图
this
.
$forceUpdate
();
}
,
// 计算主表总数量和总金额
calcTotalQuantity
()
{
let
totalPlanned
=
0
...
...
@@ -1213,28 +1242,28 @@ handleDetailSubmit(details) {
resetQuery
()
{
// 检查ref存在性
if
(
this
.
$refs
.
queryForm
)
{
this
.
queryParams
=
{
pageNum
:
1
,
pageSize
:
10
,
orderId
:
null
,
systemNo
:
null
,
orderTypeId
:
null
,
orderType
:
null
,
// 新增:订单类型重置
batchCode
:
null
,
warehouseId
:
null
,
ownerId
:
null
,
orderStatus
:
null
,
inboundDate
:
null
,
destination
:
null
,
totalPlannedQuantity
:
null
,
totalActualQuantity
:
null
,
totalPackages
:
null
,
isUsed
:
null
,
sortNo
:
null
,
createUserCode
:
null
,
updateUserCode
:
null
this
.
queryParams
=
{
pageNum
:
1
,
pageSize
:
10
,
orderId
:
null
,
systemNo
:
null
,
orderTypeId
:
null
,
orderType
:
null
,
// 新增:订单类型重置
batchCode
:
null
,
warehouseId
:
null
,
ownerId
:
null
,
orderStatus
:
null
,
inboundDate
:
null
,
destination
:
null
,
totalPlannedQuantity
:
null
,
totalActualQuantity
:
null
,
totalPackages
:
null
,
isUsed
:
null
,
sortNo
:
null
,
createUserCode
:
null
,
updateUserCode
:
null
}
}
}
this
.
queryOwnerName
=
''
this
.
queryWarehouseName
=
''
...
...
@@ -1436,82 +1465,88 @@ handleDetailSubmit(details) {
this
.
$refs
[
"form"
].
validate
(
async
(
valid
)
=>
{
if
(
valid
)
{
// 检查是否有明细数据
const
hasDetails
=
Object
.
values
(
this
.
outboundOrderItemsGroup
).
some
(
group
=>
group
.
items
.
length
>
0
)
if
(
!
hasDetails
)
{
this
.
$message
.
warning
(
'请至少添加一条明细数据'
)
return
}
// 扁平化分组数据用于提交
const
outboundOrderItemsList
=
[]
Object
.
values
(
this
.
outboundOrderItemsGroup
).
forEach
(
group
=>
{
outboundOrderItemsList
.
push
(...
group
.
items
)
}
)
// 修复:去重逻辑优化(保留最新数据)
const
uniqueDetailsMap
=
new
Map
()
outboundOrderItemsList
.
forEach
(
item
=>
{
if
(
item
.
inventoryId
)
{
uniqueDetailsMap
.
set
(
item
.
inventoryId
,
item
)
// 新增:提交前弹窗确认
const
confirmText
=
this
.
form
.
id
?
'修改'
:
'新增'
this
.
$modal
.
confirm
(
`是否确认${confirmText
}
出库单【${this.form.orderId || '未命名'
}
】?`
).
then
(
async
()
=>
{
// 检查是否有明细数据
const
hasDetails
=
Object
.
values
(
this
.
outboundOrderItemsGroup
).
some
(
group
=>
group
.
items
.
length
>
0
)
if
(
!
hasDetails
)
{
this
.
$message
.
warning
(
'请至少添加一条明细数据'
)
return
}
}
)
const
uniqueDetails
=
Array
.
from
(
uniqueDetailsMap
.
values
())
// 修改点7:构造提交数据,适配新的字段映射规则
const
submitData
=
{
...
this
.
form
,
outboundOrderId
:
this
.
form
.
id
,
orderId
:
this
.
form
.
orderId
,
orderType
:
this
.
form
.
orderType
,
// 新增:提交订单类型
outboundOrderItemsList
:
uniqueDetails
.
map
(
item
=>
{
const
{
index
,
materialUuids
,
warehouseName
,
locationName
,
...
rest
}
=
item
return
{
...
rest
,
orderId
:
null
,
outboundOrderId
:
this
.
form
.
id
||
null
,
materialName
:
item
.
materialName
||
''
,
// 【修改16】提交物料名称
inventoryId
:
rest
.
inventoryId
||
''
,
materialId
:
rest
.
materialId
||
''
,
batchCode
:
rest
.
batchCode
||
''
,
warehouseId
:
rest
.
warehouseId
||
this
.
form
.
warehouseId
||
''
,
locationId
:
rest
.
locationId
||
''
,
plannedQuantity
:
Number
(
rest
.
plannedQuantity
)
||
0
,
actualQuantity
:
Number
(
rest
.
actualQuantity
)
||
0
,
divisor
:
Number
(
rest
.
divisor
)
||
1
,
labelColor
:
Number
(
rest
.
labelColor
)
||
0
,
unitPrice
:
Number
(
rest
.
unitPrice
)
||
0.00
,
amount
:
Number
(
rest
.
amount
)
||
0.00
,
voucherNumber
:
rest
.
voucherNumber
||
''
,
itemStatus
:
Number
(
rest
.
itemStatus
)
||
1
,
shippedAt
:
rest
.
shippedAt
||
this
.
form
.
inboundDate
||
''
,
shippedBy
:
rest
.
shippedBy
||
''
,
remark
:
rest
.
remark
||
''
,
isUsed
:
1
,
sortNo
:
Number
(
rest
.
sortNo
)
||
0
}
;
// 扁平化分组数据用于提交
const
outboundOrderItemsList
=
[]
Object
.
values
(
this
.
outboundOrderItemsGroup
).
forEach
(
group
=>
{
outboundOrderItemsList
.
push
(...
group
.
items
)
}
)
}
// 调试:打印最终提交的数据
console
.
log
(
'最终提交的数据:'
,
submitData
)
// 修复:去重逻辑优化(保留最新数据)
const
uniqueDetailsMap
=
new
Map
()
outboundOrderItemsList
.
forEach
(
item
=>
{
if
(
item
.
inventoryId
)
{
uniqueDetailsMap
.
set
(
item
.
inventoryId
,
item
)
}
}
)
const
uniqueDetails
=
Array
.
from
(
uniqueDetailsMap
.
values
())
try
{
if
(
this
.
form
.
id
!=
null
)
{
await
updateOrders
(
submitData
)
this
.
$modal
.
msgSuccess
(
"修改成功"
)
}
else
{
await
addOrders
(
submitData
)
this
.
$modal
.
msgSuccess
(
"新增成功"
)
// 修改点7:构造提交数据,适配新的字段映射规则
const
submitData
=
{
...
this
.
form
,
outboundOrderId
:
this
.
form
.
id
,
orderId
:
this
.
form
.
orderId
,
orderType
:
this
.
form
.
orderType
,
// 新增:提交订单类型
outboundOrderItemsList
:
uniqueDetails
.
map
(
item
=>
{
const
{
index
,
materialUuids
,
warehouseName
,
locationName
,
...
rest
}
=
item
return
{
...
rest
,
orderId
:
null
,
outboundOrderId
:
this
.
form
.
id
||
null
,
materialName
:
item
.
materialName
||
''
,
// 【修改16】提交物料名称
inventoryId
:
rest
.
inventoryId
||
''
,
materialId
:
rest
.
materialId
||
''
,
batchCode
:
rest
.
batchCode
||
''
,
warehouseId
:
rest
.
warehouseId
||
this
.
form
.
warehouseId
||
''
,
locationId
:
rest
.
locationId
||
''
,
plannedQuantity
:
Number
(
rest
.
plannedQuantity
)
||
0
,
actualQuantity
:
Number
(
rest
.
actualQuantity
)
||
0
,
divisor
:
Number
(
rest
.
divisor
)
||
1
,
labelColor
:
Number
(
rest
.
labelColor
)
||
0
,
unitPrice
:
Number
(
rest
.
unitPrice
)
||
0.00
,
amount
:
Number
(
rest
.
amount
)
||
0.00
,
voucherNumber
:
rest
.
voucherNumber
||
''
,
itemStatus
:
Number
(
rest
.
itemStatus
)
||
1
,
shippedAt
:
rest
.
shippedAt
||
this
.
form
.
inboundDate
||
''
,
shippedBy
:
rest
.
shippedBy
||
''
,
remark
:
rest
.
remark
||
''
,
isUsed
:
1
,
sortNo
:
Number
(
rest
.
sortNo
)
||
0
}
;
}
)
}
this
.
open
=
false
this
.
getList
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
{
const
errorMsg
=
error
?.
response
?.
data
?.
msg
||
'库存被修改请重新确认'
this
.
$modal
.
msgError
(
errorMsg
)
// 调试:打印最终提交的数据
console
.
log
(
'最终提交的数据:'
,
submitData
)
try
{
if
(
this
.
form
.
id
!=
null
)
{
await
updateOrders
(
submitData
)
this
.
$modal
.
msgSuccess
(
"修改成功"
)
}
else
{
await
addOrders
(
submitData
)
this
.
$modal
.
msgSuccess
(
"新增成功"
)
}
this
.
open
=
false
this
.
getList
()
}
catch
(
error
)
{
if
(
error
!==
'cancel'
)
{
const
errorMsg
=
error
?.
response
?.
data
?.
msg
||
'库存被修改请重新确认'
this
.
$modal
.
msgError
(
errorMsg
)
}
}
}
}
).
catch
(()
=>
{
// 取消确认时不执行任何操作
}
)
}
}
)
}
,
...
...
@@ -1537,70 +1572,4 @@ handleDetailSubmit(details) {
}
}
}
<
/script
>
<
style
scoped
>
/* 页面容器样式 */
.
page
-
container
{
background
:
#
fff
;
padding
:
16
px
;
border
-
radius
:
4
px
;
box
-
shadow
:
0
2
px
12
px
0
rgba
(
0
,
0
,
0
,
0.04
);
margin
-
top
:
16
px
;
}
/* 表格容器样式 */
.
table
-
container
{
margin
-
top
:
16
px
;
height
:
calc
(
100
vh
-
280
px
);
}
/* 弹窗内表单滚动优化 */
.
el
-
dialog__body
{
max
-
height
:
70
vh
;
overflow
-
y
:
auto
;
padding
-
right
:
10
px
;
}
/* 自定义滚动条 */
.
el
-
dialog__body
::
-
webkit
-
scrollbar
{
width
:
6
px
;
}
.
el
-
dialog__body
::
-
webkit
-
scrollbar
-
thumb
{
background
-
color
:
#
ddd
;
border
-
radius
:
3
px
;
}
/* 明细表格样式优化 */
.
el
-
table
{
--
el
-
table
-
row
-
hover
-
bg
-
color
:
#
f8f9fa
;
}
/* 空数据提示样式 */
.
empty
-
tip
{
color
:
#
999
;
font
-
size
:
14
px
;
}
/* 物料分组样式 */
.
material
-
group
{
border
:
1
px
solid
#
e6e6e6
;
border
-
radius
:
6
px
;
padding
:
10
px
;
}
.
group
-
header
{
display
:
flex
;
align
-
items
:
center
;
justify
-
content
:
space
-
between
;
}
.
mb10
{
margin
-
bottom
:
10
px
;
}
.
mb8
{
margin
-
bottom
:
8
px
;
}
<
/style>
\ No newline at end of file
<
/script>
\ No newline at end of file
ruoyi-admin-vue/src/views/inventory/report_view/inventory_detail.vue
View file @
db0c0a3a
...
...
@@ -138,7 +138,15 @@
<el-table-column
label=
"物料名称"
align=
"center"
prop=
"materialName"
width=
"150"
/>
<el-table-column
label=
"SAP物料号"
align=
"center"
prop=
"sapNo"
width=
"120"
/>
<el-table-column
label=
"TS Code"
align=
"center"
prop=
"tsCode"
width=
"120"
/>
<el-table-column
label=
"危险类别"
align=
"center"
prop=
"hazard"
width=
"120"
/>
<el-table-column
label=
"危险类别"
align=
"center"
prop=
"hazardId"
width=
"120"
>
<
template
slot-scope=
"scope"
>
<el-tag
:type=
"getDictListClass('danger_type',scope.row.hazardId)"
size=
"small"
>
{{
getDictLabel
(
'danger_type'
,
scope
.
row
.
hazardId
)
}}
</el-tag>
</
template
>
</el-table-column>
<el-table-column
label=
"规格型号"
align=
"center"
prop=
"specification"
width=
"120"
/>
<el-table-column
label=
"计量单位"
align=
"center"
prop=
"materialUnit"
width=
"120"
/>
<el-table-column
label=
"单位重量"
align=
"center"
prop=
"unitWeight"
width=
"120"
>
...
...
@@ -232,7 +240,15 @@
<el-table-column
label=
"物料名称"
align=
"center"
prop=
"materialName"
width=
"150"
/>
<el-table-column
label=
"SAP物料号"
align=
"center"
prop=
"sapNo"
width=
"120"
/>
<el-table-column
label=
"TS Code"
align=
"center"
prop=
"tsCode"
width=
"120"
/>
<el-table-column
label=
"危险类别"
align=
"center"
prop=
"hazard"
width=
"120"
/>
<el-table-column
label=
"危险类别"
align=
"center"
prop=
"hazardId"
width=
"120"
>
<
template
slot-scope=
"scope"
>
<el-tag
:type=
"getDictListClass('danger_type',scope.row.hazardId)"
size=
"small"
>
{{
getDictLabel
(
'danger_type'
,
scope
.
row
.
hazardId
)
}}
</el-tag>
</
template
>
</el-table-column>
<!-- <el-table-column label="规格型号" align="center" prop="specification" width="120" /> -->
<!-- <el-table-column label="入库单号" align="center" prop="orderId" width="150" /> -->
<el-table-column
label=
"批次"
align=
"center"
prop=
"batchId"
width=
"120"
/>
...
...
@@ -265,6 +281,7 @@ import ImportExcel from "@/components/ImportExcel"
export
default
{
name
:
"InventoryDetail"
,
dicts
:
[
'danger_type'
],
components
:
{
RightToolbar
,
PageTitle
,
...
...
@@ -333,6 +350,19 @@ export default {
this
.
getList
()
},
methods
:
{
//从表格中的值当作键获取字典lebel
getDictLabel
(
dictType
,
value
){
if
(
!
value
||
!
this
.
dict
?.
type
?.[
dictType
])
return
'-'
const
dictItem
=
this
.
dict
.
type
[
dictType
].
find
(
item
=>
item
.
value
===
value
)
return
dictItem
?.
label
||
'-'
},
//从表格中的值当作键获取字典listClass
getDictListClass
(
dictType
,
value
){
if
(
!
value
||
!
this
.
dict
?.
type
?.[
dictType
])
return
'-'
const
dictItem
=
this
.
dict
.
type
[
dictType
].
find
(
item
=>
item
.
value
===
value
)
return
dictItem
?.
label
||
'-'
},
/** 查询库存明细列表 */
getList
()
{
this
.
loading
=
true
...
...
ruoyi-admin-vue/src/views/inventory/warehouses/index.vue
View file @
db0c0a3a
...
...
@@ -36,14 +36,7 @@
@
click=
"handleExport"
v-hasPermi=
"['inventory:warehouses:export']"
>
导出
</el-button>
<el-button
type=
"info"
plain
icon=
"el-icon-upload2"
size=
"medium"
@
click=
"handleImport"
v-hasPermi=
"['inventory:warehouses:add']"
>
导入
</el-button>
</
template
>
</PageTitle>
...
...
ruoyi-admin/src/main/java/com/ruoyi/web/controller/inventory/InboundOrdersController.java
View file @
db0c0a3a
package
com
.
ruoyi
.
web
.
controller
.
inventory
;
import
java.io.IOException
;
import
java.lang.reflect.Field
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
java.util.stream.Collectors
;
import
com.ruoyi.common.core.domain.entity.Materials
;
import
com.alibaba.excel.EasyExcel
;
import
com.alibaba.excel.context.AnalysisContext
;
import
com.alibaba.excel.event.AnalysisEventListener
;
import
com.alibaba.excel.exception.ExcelAnalysisException
;
import
com.ruoyi.common.annotation.Excel
;
import
com.ruoyi.common.exception.ServiceException
;
import
com.ruoyi.common.utils.uuid.UUID
;
import
javax.servlet.http.HttpServletResponse
;
import
com.ruoyi.inventory.domain.
InboundOrderItems
;
import
com.ruoyi.inventory.domain.
vo.inboundVO.InboundFinishTemplateVO
;
import
com.ruoyi.inventory.domain.vo.InboundMaterialTotalVO
;
import
com.ruoyi.inventory.domain.vo.InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.inboundVO.InboundTRDCTemplateVO
;
import
com.ruoyi.inventory.domain.vo.inboundVO.InboundTemplateVO
;
import
com.ruoyi.inventory.service.impl.InboundOrdersServiceImpl
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.util.CollectionUtils
;
...
...
@@ -37,7 +51,7 @@ public class InboundOrdersController extends BaseController
{
@Autowired
private
IInboundOrdersService
inboundOrdersService
;
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
InboundOrdersServiceImpl
.
class
);
/**
* 查询入库单主列表
*/
...
...
@@ -113,10 +127,22 @@ public class InboundOrdersController extends BaseController
@PreAuthorize
(
"@ss.hasPermi('inventory:inbound:importTemplate')"
)
@Log
(
title
=
"入库导入模板"
,
businessType
=
BusinessType
.
IMPORT
)
@PostMapping
(
"/importTemplate"
)
public
void
importTemplate
(
HttpServletResponse
response
)
public
void
importTemplate
(
HttpServletResponse
response
,
@RequestParam
(
"orderType"
)
Integer
orderType
)
{
ExcelUtil
<
InboundTemplateVO
>
util
=
new
ExcelUtil
<
InboundTemplateVO
>(
InboundTemplateVO
.
class
);
util
.
importTemplateExcel
(
response
,
"入库单及入库物料明细信息"
);
switch
(
orderType
){
case
1
:
ExcelUtil
<
InboundTemplateVO
>
util
=
new
ExcelUtil
<
InboundTemplateVO
>(
InboundTemplateVO
.
class
);
util
.
importTemplateExcel
(
response
,
"入库单及入库物料明细信息"
);
break
;
case
2
:
ExcelUtil
<
InboundFinishTemplateVO
>
util1
=
new
ExcelUtil
<
InboundFinishTemplateVO
>(
InboundFinishTemplateVO
.
class
);
util1
.
importTemplateExcel
(
response
,
"成品入库单及入库物料明细信息"
);
break
;
case
3
:
ExcelUtil
<
InboundTRDCTemplateVO
>
util2
=
new
ExcelUtil
<
InboundTRDCTemplateVO
>(
InboundTRDCTemplateVO
.
class
);
util2
.
importTemplateExcel
(
response
,
"TRDC退库入库单及入库物料明细信息"
);
break
;
}
}
/**
...
...
@@ -126,62 +152,117 @@ public class InboundOrdersController extends BaseController
@Log
(
title
=
"入库信息导入"
,
businessType
=
BusinessType
.
IMPORT
)
@PostMapping
(
"/import"
)
public
AjaxResult
importTemplate
(
@RequestParam
(
"file"
)
MultipartFile
file
,
// 接收 true/false
@RequestParam
(
"updateSupport"
)
Integer
updateSupport
,
@RequestParam
(
value
=
"orderType"
,
required
=
false
)
Integer
orderType
)
throws
Exception
{
@RequestParam
(
value
=
"orderType"
,
required
=
false
)
Integer
orderType
)
throws
Exception
{
// 防护1:校验文件非空
if
(
file
==
null
||
file
.
isEmpty
())
{
return
error
(
"导入文件不能为空!"
);
}
// 防护2:校验文件格式
String
fileName
=
file
.
getOriginalFilename
();
if
(
!
fileName
.
endsWith
(
".xlsx"
)
&&
!
fileName
.
endsWith
(
".xls"
))
{
if
(
fileName
==
null
||
(!
fileName
.
endsWith
(
".xlsx"
)
&&
!
fileName
.
endsWith
(
".xls"
)
))
{
return
error
(
"仅支持Excel格式文件(.xlsx/.xls)!"
);
}
// 第二步:校验Excel列名是否匹配模板(核心!拦截非模板数据)
List
<
String
>
templateColumns
=
Arrays
.
asList
(
"入库日期"
,
"SAP No"
,
"物料名称"
,
"TS Code"
,
"货主"
,
"批号"
,
"计划数量"
,
"单号"
,
"系统编号"
,
"件重"
,
"约数"
,
"实际件数"
,
"实发数量"
,
"仓库"
,
"库位"
,
"标签颜色"
,
"凭证号"
,
"单价"
,
"备注"
,
"订单类型"
,
"收货人"
,
"物料备注"
);
List
<
String
>
excelColumns
=
ExcelUtil
.
getExcelHeader
(
file
.
getInputStream
());
// 自定义方法读取表头
if
(
CollectionUtils
.
isEmpty
(
excelColumns
)
||
!
excelColumns
.
containsAll
(
templateColumns
))
{
return
AjaxResult
.
error
(
"导入文件不是标准模板!请下载官方模板后填写(缺失列:"
+
getMissingColumns
(
templateColumns
,
excelColumns
)
+
")"
);
// 防护3:校验orderType非空且合法
if
(
orderType
==
null
||
!
Arrays
.
asList
(
1
,
2
,
3
).
contains
(
orderType
))
{
return
error
(
"导入类型不能为空,仅支持1/2/3!"
);
}
ExcelUtil
<
InboundTemplateVO
>
util
=
new
ExcelUtil
<
InboundTemplateVO
>(
InboundTemplateVO
.
class
);
List
<
InboundTemplateVO
>
inboundOrders
=
util
.
importExcel
(
file
.
getInputStream
());
// 防护3:拦截空列表,避免 Service 层处理空数据
if
(
CollectionUtils
.
isEmpty
(
inboundOrders
))
{
return
error
(
"Excel中未解析到有效数据,请检查模板是否正确!"
);
// 2. 解析Excel表头(适配EasyExcel 2.x,无interrupt、无readRowNumber)
List
<
String
>
headerList
=
new
ArrayList
<>();
// 标记:是否已解析表头(避免重复处理)
AtomicBoolean
headerParsed
=
new
AtomicBoolean
(
false
);
try
{
EasyExcel
.
read
(
file
.
getInputStream
(),
new
AnalysisEventListener
<
Object
>()
{
// 解析表头(2.x 中invokeHeadMap只会执行一次)
@Override
public
void
invokeHeadMap
(
Map
<
Integer
,
String
>
headMap
,
AnalysisContext
context
)
{
// 仅首次执行时解析表头
if
(!
headerParsed
.
get
())
{
for
(
String
header
:
headMap
.
values
())
{
headerList
.
add
(
header
.
trim
());
// 去空格存入
}
headerParsed
.
set
(
true
);
// 标记表头已解析完成
log
.
info
(
"Excel表头解析完成,表头列表:{}"
,
headerList
);
}
}
// 解析数据行(表头解析完成后,直接返回不处理)
@Override
public
void
invoke
(
Object
data
,
AnalysisContext
context
)
{
// 逻辑终止:表头解析完后,数据行直接跳过
return
;
}
// 解析完成(空实现即可)
@Override
public
void
doAfterAllAnalysed
(
AnalysisContext
context
)
{}
})
.
sheet
()
// 读取第一个sheet
.
headRowNumber
(
1
)
// 指定表头在第1行(2.x 核心配置)
.
doRead
();
// 执行解析
}
catch
(
IOException
e
)
{
log
.
error
(
"解析Excel表头失败"
,
e
);
return
AjaxResult
.
error
(
"解析Excel文件失败:"
+
e
.
getMessage
());
}
// 防护4:表头解析为空的情况
if
(
CollectionUtils
.
isEmpty
(
headerList
))
{
return
error
(
"未解析到Excel表头,请检查模板是否有表头行!"
);
}
String
operName
=
getUsername
();
String
message
=
inboundOrdersService
.
importInboundOrders
(
inboundOrders
,
updateSupport
,
operName
,
orderType
);
// 3. 通用导入逻辑(抽取重复代码,避免冗余)
String
message
=
handleImport
(
getVOClassByOrderType
(
orderType
),
file
,
headerList
,
updateSupport
,
getUsername
()
,
orderType
);
return
success
(
message
);
}
// 辅助方法:获取缺失的列名
/**
* 根据orderType获取对应的VO类
*/
private
Class
<?>
getVOClassByOrderType
(
Integer
orderType
)
{
switch
(
orderType
)
{
case
1
:
return
InboundTemplateVO
.
class
;
case
2
:
return
InboundFinishTemplateVO
.
class
;
case
3
:
return
InboundTRDCTemplateVO
.
class
;
default
:
throw
new
ServiceException
(
"不支持的导入类型,请联系管理员"
+
orderType
);
}
}
/**
* 通用导入逻辑(泛型适配不同VO)
*/
private
<
T
>
String
handleImport
(
Class
<
T
>
clazz
,
MultipartFile
file
,
List
<
String
>
headerList
,
Integer
updateSupport
,
String
operName
,
Integer
orderType
)
throws
Exception
{
// 反射读取VO中@Excel注解的必填表头
List
<
String
>
requiredExcelHeads
=
new
ArrayList
<>();
Field
[]
fields
=
clazz
.
getDeclaredFields
();
for
(
Field
field
:
fields
)
{
if
(
field
.
isAnnotationPresent
(
Excel
.
class
))
{
requiredExcelHeads
.
add
(
field
.
getAnnotation
(
Excel
.
class
).
name
().
trim
());
}
}
// 校验表头是否包含所有必填项
if
(!
headerList
.
containsAll
(
requiredExcelHeads
))
{
List
<
String
>
missingHeads
=
requiredExcelHeads
.
stream
()
.
filter
(
head
->
!
headerList
.
contains
(
head
))
.
collect
(
Collectors
.
toList
());
return
"导入数据字段与目标模板不一致,请检查!缺失字段:"
+
String
.
join
(
"、"
,
missingHeads
);
}
// 解析Excel数据(若依ExcelUtil适配2.x,无需修改)
ExcelUtil
<
T
>
util
=
new
ExcelUtil
<>(
clazz
);
List
<
T
>
dataList
=
util
.
importExcel
(
file
.
getInputStream
());
if
(
CollectionUtils
.
isEmpty
(
dataList
))
{
return
"Excel中未解析到有效数据,请检查模板是否正确!"
;
}
// 调用Service导入(需确保Service支持泛型列表,或强转Object)
return
inboundOrdersService
.
importInboundOrders
(
dataList
,
updateSupport
,
operName
,
orderType
);
}
// 辅助方法:获取缺失的列名(备用)
private
String
getMissingColumns
(
List
<
String
>
template
,
List
<
String
>
excel
)
{
return
template
.
stream
()
.
filter
(
col
->
!
excel
.
contains
(
col
))
...
...
ruoyi-common/src/main/java/com/ruoyi/common/config/WarehouseConfig.java
0 → 100644
View file @
db0c0a3a
package
com
.
ruoyi
.
common
.
config
;
/**
* 仓库配置类(存储默认仓库、常用仓库ID等)
*/
public
class
WarehouseConfig
{
/**
* 默认出库仓库ID(核心默认值)
*/
public
static
final
String
DEFAULT_WAREHOUSE_ID
=
"572ba484-199c-45d9-9735-610928ed5c70"
;
}
\ No newline at end of file
ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/Materials.java
View file @
db0c0a3a
...
...
@@ -11,6 +11,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
* @author ruoyi
* @date 2025-11-28
*/
public
class
Materials
extends
BaseEntity
{
private
static
final
long
serialVersionUID
=
1L
;
...
...
@@ -18,94 +19,115 @@ public class Materials extends BaseEntity
/** 编号 */
private
String
id
;
/** 物料编码 检索条件 */
private
String
materialCode
;
@Excel
(
name
=
"NO."
)
private
Long
no
;
/** 货主 数据库暂无字段 */
@Excel
(
name
=
"货主"
)
private
String
ownerId
;
/** SAP物料号 检索条件 */
@Excel
(
name
=
"
SAP物料号
"
)
@Excel
(
name
=
"
产品代码
"
)
private
String
sapNo
;
/** 是否激活 Y-是 N-否 */
@Excel
(
name
=
"激活"
)
private
Long
isActive
;
/** 物料名称 检索条件 */
@Excel
(
name
=
"
物料名称
"
)
@Excel
(
name
=
"
中文描述
"
)
private
String
materialName
;
/** 物料名称 检索条件 */
@Excel
(
name
=
"英文描述"
)
private
String
materialEname
;
/** 总重量 */
@Excel
(
name
=
"毛重"
)
private
Long
totalWeight
;
/** 单位重量 */
@Excel
(
name
=
"净重"
)
private
Long
unitWeight
;
/** 包装重量 */
@Excel
(
name
=
"皮重"
)
private
Long
packageWeight
;
/** 体积 */
@Excel
(
name
=
"体积"
)
private
Long
volume
;
/** 单价 */
@Excel
(
name
=
"单价"
)
private
Long
unitPrice
;
/** 备注 */
@Excel
(
name
=
"备注"
)
private
String
remark
;
/** 物料编码 检索条件 */
private
String
materialCode
;
/** TS Code 检索条件 */
@Excel
(
name
=
"TS Code"
)
//
@Excel(name = "TS Code")
private
String
tsCode
;
/** 物料分类 检索条件 */
@Excel
(
name
=
"物料分类"
)
//
@Excel(name = "物料分类")
private
String
categoryCode
;
/** 危险类别ID 字典 */
@Excel
(
name
=
"危险类别ID"
)
//
@Excel(name = "危险类别ID")
private
String
hazardId
;
/** 规格型号 检索条件 */
@Excel
(
name
=
"规格型号"
)
//
@Excel(name = "规格型号")
private
String
specification
;
/** 计量单位 字典 */
@Excel
(
name
=
"计量单位"
)
//
@Excel(name = "计量单位")
private
String
materialUnit
;
/** 单位重量 */
@Excel
(
name
=
"单位重量"
)
private
Long
unitWeight
;
/** 包装重量 */
@Excel
(
name
=
"包装重量"
)
private
Long
packageWeight
;
/** 总重量 */
@Excel
(
name
=
"总重量"
)
private
Long
totalWeight
;
/** 体积 */
@Excel
(
name
=
"体积"
)
private
Long
volume
;
/** 保质期天数 */
@Excel
(
name
=
"保质期天数"
)
//
@Excel(name = "保质期天数")
private
Long
shelfLifeDays
;
/** 存储温度要求 */
@Excel
(
name
=
"存储温度要求"
)
//
@Excel(name = "存储温度要求")
private
String
storageTemperature
;
/** 特殊存储要求 */
@Excel
(
name
=
"特殊存储要求"
)
//
@Excel(name = "特殊存储要求")
private
String
specialRequirements
;
/** 是否批次管理 1-是 0-否 */
@Excel
(
name
=
"是否批次管理 1-是 0-否"
)
//
@Excel(name = "是否批次管理 1-是 0-否")
private
Long
isBatchManaged
;
/** 是否序列号管理 1-是 0-否 */
@Excel
(
name
=
"是否序列号管理 1-是 0-否"
)
//
@Excel(name = "是否序列号管理 1-是 0-否")
private
Long
isSerialManaged
;
/** 最低库存 */
@Excel
(
name
=
"最低库存"
)
//
@Excel(name = "最低库存")
private
Long
minStockLevel
;
/** 最高库存 */
@Excel
(
name
=
"最高库存"
)
//
@Excel(name = "最高库存")
private
Long
maxStockLevel
;
/** 是否正在使用 1-是 0-否 */
@Excel
(
name
=
"是否正在使用 1-是 0-否"
)
//
@Excel(name = "是否正在使用 1-是 0-否")
private
Long
isUsed
;
/** 是否激活 1-是 0-否 */
@Excel
(
name
=
"是否激活 1-是 0-否"
)
private
Long
isActive
;
/** 风险等级 字典 */
@Excel
(
name
=
"风险等级"
)
//
@Excel(name = "风险等级")
private
String
riskLevel
;
/** 排序 */
@Excel
(
name
=
"排序"
)
//
@Excel(name = "排序")
private
Long
sortNo
;
/** 创建日期 */
...
...
@@ -114,291 +136,290 @@ public class Materials extends BaseEntity
/** 排序号 */
private
String
updateUserCode
;
public
void
setId
(
String
id
)
{
this
.
id
=
id
;
}
public
String
getId
()
{
public
String
getId
()
{
return
id
;
}
public
void
setMaterialCode
(
String
materialCode
)
{
this
.
materialCode
=
materialCode
;
public
void
setId
(
String
id
)
{
this
.
id
=
id
;
}
public
String
getMaterialCode
()
{
return
materialCode
;
public
Long
getNo
()
{
return
no
;
}
public
void
setMaterialName
(
String
materialName
)
{
this
.
materialName
=
materialName
;
public
void
setNo
(
Long
no
)
{
this
.
no
=
no
;
}
public
String
getMaterialName
()
{
return
materialName
;
public
String
getOwnerId
()
{
return
ownerId
;
}
public
void
setSapNo
(
String
sapNo
)
{
this
.
sapNo
=
sapNo
;
public
void
setOwnerId
(
String
ownerId
)
{
this
.
ownerId
=
ownerId
;
}
public
String
getSapNo
()
{
public
String
getSapNo
()
{
return
sapNo
;
}
public
void
setTsCode
(
String
tsCode
)
{
this
.
tsCode
=
tsCode
;
public
void
setSapNo
(
String
sapNo
)
{
this
.
sapNo
=
sapNo
;
}
public
String
getTsCode
()
{
return
tsCode
;
public
Long
getIsActive
()
{
return
isActive
;
}
public
void
setCategoryCode
(
String
categoryCode
)
{
this
.
categoryCode
=
categoryCode
;
public
void
setIsActive
(
Long
isActive
)
{
this
.
isActive
=
isActive
;
}
public
String
getCategoryCode
()
{
return
categoryCode
;
public
String
getMaterialName
()
{
return
materialName
;
}
public
void
setHazardId
(
String
hazardId
)
{
this
.
hazardId
=
hazardId
;
public
void
setMaterialName
(
String
materialName
)
{
this
.
materialName
=
materialName
;
}
public
String
getHazardId
()
{
return
hazardId
;
public
String
getMaterialEname
()
{
return
materialEname
;
}
public
void
setSpecification
(
String
specification
)
{
this
.
specification
=
specification
;
public
void
setMaterialEname
(
String
materialEname
)
{
this
.
materialEname
=
materialEname
;
}
public
String
getSpecification
()
{
return
specification
;
public
Long
getTotalWeight
()
{
return
totalWeight
;
}
public
void
setMaterialUnit
(
String
materialUnit
)
{
this
.
materialUnit
=
materialUnit
;
public
void
setTotalWeight
(
Long
totalWeight
)
{
this
.
totalWeight
=
totalWeight
;
}
public
String
getMaterialUnit
()
{
return
materialUnit
;
public
Long
getUnitWeight
()
{
return
unitWeight
;
}
public
void
setUnitWeight
(
Long
unitWeight
)
{
public
void
setUnitWeight
(
Long
unitWeight
)
{
this
.
unitWeight
=
unitWeight
;
}
public
Long
getUnitWeight
()
{
return
unitWeight
;
public
Long
getPackageWeight
()
{
return
packageWeight
;
}
public
void
setPackageWeight
(
Long
packageWeight
)
{
public
void
setPackageWeight
(
Long
packageWeight
)
{
this
.
packageWeight
=
packageWeight
;
}
public
Long
getPackageWeight
()
{
return
packageWeight
;
public
Long
getVolume
()
{
return
volume
;
}
public
void
setTotalWeight
(
Long
totalWeight
)
{
this
.
totalWeight
=
totalWeight
;
public
void
setVolume
(
Long
volume
)
{
this
.
volume
=
volume
;
}
public
Long
getTotalWeight
()
{
return
totalWeight
;
public
Long
getUnitPrice
()
{
return
unitPrice
;
}
public
void
setVolume
(
Long
volume
)
{
this
.
volume
=
volume
;
public
void
setUnitPrice
(
Long
unitPrice
)
{
this
.
unitPrice
=
unitPrice
;
}
public
Long
getVolume
()
{
return
volume
;
@Override
public
String
getRemark
()
{
return
remark
;
}
public
void
setShelfLifeDays
(
Long
shelfLifeDays
)
{
this
.
shelfLifeDays
=
shelfLifeDays
;
@Override
public
void
setRemark
(
String
remark
)
{
this
.
remark
=
remark
;
}
public
String
getMaterialCode
()
{
return
materialCode
;
}
public
void
setMaterialCode
(
String
materialCode
)
{
this
.
materialCode
=
materialCode
;
}
public
String
getTsCode
()
{
return
tsCode
;
}
public
void
setTsCode
(
String
tsCode
)
{
this
.
tsCode
=
tsCode
;
}
public
String
getCategoryCode
()
{
return
categoryCode
;
}
public
void
setCategoryCode
(
String
categoryCode
)
{
this
.
categoryCode
=
categoryCode
;
}
public
String
getHazardId
()
{
return
hazardId
;
}
public
void
setHazardId
(
String
hazardId
)
{
this
.
hazardId
=
hazardId
;
}
public
String
getSpecification
()
{
return
specification
;
}
public
Long
getShelfLifeDays
()
{
public
void
setSpecification
(
String
specification
)
{
this
.
specification
=
specification
;
}
public
String
getMaterialUnit
()
{
return
materialUnit
;
}
public
void
setMaterialUnit
(
String
materialUnit
)
{
this
.
materialUnit
=
materialUnit
;
}
public
Long
getShelfLifeDays
()
{
return
shelfLifeDays
;
}
public
void
setStorageTemperature
(
String
storageTemperature
)
{
this
.
storageTemperature
=
storageTemperature
;
public
void
setShelfLifeDays
(
Long
shelfLifeDays
)
{
this
.
shelfLifeDays
=
shelfLifeDays
;
}
public
String
getStorageTemperature
()
{
public
String
getStorageTemperature
()
{
return
storageTemperature
;
}
public
void
setSpecialRequirements
(
String
specialRequirements
)
{
this
.
specialRequirements
=
specialRequirements
;
public
void
setStorageTemperature
(
String
storageTemperature
)
{
this
.
storageTemperature
=
storageTemperature
;
}
public
String
getSpecialRequirements
()
{
public
String
getSpecialRequirements
()
{
return
specialRequirements
;
}
public
void
setIsBatchManaged
(
Long
isBatchManaged
)
{
this
.
isBatchManaged
=
isBatchManaged
;
public
void
setSpecialRequirements
(
String
specialRequirements
)
{
this
.
specialRequirements
=
specialRequirements
;
}
public
Long
getIsBatchManaged
()
{
public
Long
getIsBatchManaged
()
{
return
isBatchManaged
;
}
public
void
setIsSerialManaged
(
Long
isSerialManaged
)
{
this
.
isSerialManaged
=
isSerialManaged
;
public
void
setIsBatchManaged
(
Long
isBatchManaged
)
{
this
.
isBatchManaged
=
isBatchManaged
;
}
public
Long
getIsSerialManaged
()
{
public
Long
getIsSerialManaged
()
{
return
isSerialManaged
;
}
public
void
setMinStockLevel
(
Long
minStockLevel
)
{
this
.
minStockLevel
=
minStockLevel
;
public
void
setIsSerialManaged
(
Long
isSerialManaged
)
{
this
.
isSerialManaged
=
isSerialManaged
;
}
public
Long
getMinStockLevel
()
{
public
Long
getMinStockLevel
()
{
return
minStockLevel
;
}
public
void
setMaxStockLevel
(
Long
maxStockLevel
)
{
this
.
maxStockLevel
=
maxStockLevel
;
public
void
setMinStockLevel
(
Long
minStockLevel
)
{
this
.
minStockLevel
=
minStockLevel
;
}
public
Long
getMaxStockLevel
()
{
public
Long
getMaxStockLevel
()
{
return
maxStockLevel
;
}
public
Long
getIsUsed
()
{
return
isUsed
;
}
public
void
setIsUsed
(
Long
isUsed
)
{
this
.
isUsed
=
isUsed
;
}
public
void
setIsActive
(
Long
isActive
)
{
this
.
isActive
=
isActive
;
public
void
setMaxStockLevel
(
Long
maxStockLevel
)
{
this
.
maxStockLevel
=
maxStockLevel
;
}
public
Long
getIsActive
()
{
return
isActive
;
public
Long
getIsUsed
()
{
return
isUsed
;
}
public
void
setRiskLevel
(
String
riskLevel
)
{
this
.
riskLevel
=
riskLevel
;
public
void
setIsUsed
(
Long
isUsed
)
{
this
.
isUsed
=
isUsed
;
}
public
String
getRiskLevel
()
{
public
String
getRiskLevel
()
{
return
riskLevel
;
}
public
void
setSortNo
(
Long
sortNo
)
{
this
.
sortNo
=
sortNo
;
public
void
setRiskLevel
(
String
riskLevel
)
{
this
.
riskLevel
=
riskLevel
;
}
public
Long
getSortNo
()
{
public
Long
getSortNo
()
{
return
sortNo
;
}
public
void
setCreateUserCode
(
String
createUserCode
)
{
this
.
createUserCode
=
createUserCode
;
public
void
setSortNo
(
Long
sortNo
)
{
this
.
sortNo
=
sortNo
;
}
public
String
getCreateUserCode
()
{
public
String
getCreateUserCode
()
{
return
createUserCode
;
}
public
void
setUpdateUserCode
(
String
updateUserCode
)
{
this
.
updateUserCode
=
updateUserCode
;
public
void
setCreateUserCode
(
String
createUserCode
)
{
this
.
createUserCode
=
createUserCode
;
}
public
String
getUpdateUserCode
()
{
public
String
getUpdateUserCode
()
{
return
updateUserCode
;
}
public
void
setUpdateUserCode
(
String
updateUserCode
)
{
this
.
updateUserCode
=
updateUserCode
;
}
@Override
public
String
toString
()
{
return
new
ToStringBuilder
(
this
,
ToStringStyle
.
MULTI_LINE_STYLE
)
.
append
(
"id"
,
getId
())
.
append
(
"materialCode"
,
getMaterialCode
())
.
append
(
"materialName"
,
getMaterialName
())
.
append
(
"sapNo"
,
getSapNo
())
.
append
(
"tsCode"
,
getTsCode
())
.
append
(
"categoryCode"
,
getCategoryCode
())
.
append
(
"hazardId"
,
getHazardId
())
.
append
(
"specification"
,
getSpecification
())
.
append
(
"materialUnit"
,
getMaterialUnit
())
.
append
(
"unitWeight"
,
getUnitWeight
())
.
append
(
"packageWeight"
,
getPackageWeight
())
.
append
(
"totalWeight"
,
getTotalWeight
())
.
append
(
"volume"
,
getVolume
())
.
append
(
"shelfLifeDays"
,
getShelfLifeDays
())
.
append
(
"storageTemperature"
,
getStorageTemperature
())
.
append
(
"specialRequirements"
,
getSpecialRequirements
())
.
append
(
"isBatchManaged"
,
getIsBatchManaged
())
.
append
(
"isSerialManaged"
,
getIsSerialManaged
())
.
append
(
"minStockLevel"
,
getMinStockLevel
())
.
append
(
"maxStockLevel"
,
getMaxStockLevel
())
.
append
(
"isUsed"
,
getIsUsed
())
.
append
(
"isActive"
,
getIsActive
())
.
append
(
"riskLevel"
,
getRiskLevel
())
.
append
(
"sortNo"
,
getSortNo
())
.
append
(
"createTime"
,
getCreateTime
())
.
append
(
"createUserCode"
,
getCreateUserCode
())
.
append
(
"updateTime"
,
getUpdateTime
())
.
append
(
"updateUserCode"
,
getUpdateUserCode
())
.
toString
();
return
"Materials{"
+
"id='"
+
id
+
'\''
+
", no="
+
no
+
", ownerId='"
+
ownerId
+
'\''
+
", sapNo='"
+
sapNo
+
'\''
+
", isActive="
+
isActive
+
", materialName='"
+
materialName
+
'\''
+
", materialEname='"
+
materialEname
+
'\''
+
", totalWeight="
+
totalWeight
+
", unitWeight="
+
unitWeight
+
", packageWeight="
+
packageWeight
+
", volume="
+
volume
+
", unitPrice="
+
unitPrice
+
", remark='"
+
remark
+
'\''
+
", materialCode='"
+
materialCode
+
'\''
+
", tsCode='"
+
tsCode
+
'\''
+
", categoryCode='"
+
categoryCode
+
'\''
+
", hazardId='"
+
hazardId
+
'\''
+
", specification='"
+
specification
+
'\''
+
", materialUnit='"
+
materialUnit
+
'\''
+
", shelfLifeDays="
+
shelfLifeDays
+
", storageTemperature='"
+
storageTemperature
+
'\''
+
", specialRequirements='"
+
specialRequirements
+
'\''
+
", isBatchManaged="
+
isBatchManaged
+
", isSerialManaged="
+
isSerialManaged
+
", minStockLevel="
+
minStockLevel
+
", maxStockLevel="
+
maxStockLevel
+
", isUsed="
+
isUsed
+
", riskLevel='"
+
riskLevel
+
'\''
+
", sortNo="
+
sortNo
+
", createUserCode='"
+
createUserCode
+
'\''
+
", updateUserCode='"
+
updateUserCode
+
'\''
+
'}'
;
}
}
ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
View file @
db0c0a3a
...
...
@@ -719,4 +719,5 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
}
return
sb
.
toString
();
}
}
\ No newline at end of file
ruoyi-inventory/src/main/java/com/ruoyi/inventory/controller/OutboundOrderItemsController.java
View file @
db0c0a3a
...
...
@@ -3,7 +3,7 @@ package com.ruoyi.inventory.controller;
import
java.util.List
;
import
javax.servlet.http.HttpServletResponse
;
import
com.ruoyi.inventory.domain.vo.InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.
inboundVO.
InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.OutboundOrdersSummaryVO
;
import
com.ruoyi.inventory.domain.vo.OutboundTemplateVO
;
import
org.springframework.security.access.prepost.PreAuthorize
;
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/controller/OutboundOrdersController.java
View file @
db0c0a3a
...
...
@@ -6,7 +6,7 @@ import javax.servlet.http.HttpServletResponse;
import
com.alibaba.fastjson2.JSONObject
;
import
com.ruoyi.inventory.domain.Inventory
;
import
com.ruoyi.inventory.domain.vo.InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.
inboundVO.
InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.OutboundTemplateVO
;
import
org.springframework.security.access.prepost.PreAuthorize
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/InventoryTransactions.java
View file @
db0c0a3a
...
...
@@ -2,6 +2,7 @@ package com.ruoyi.inventory.domain;
import
java.util.Date
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
lombok.Data
;
import
org.apache.commons.lang3.builder.ToStringBuilder
;
import
org.apache.commons.lang3.builder.ToStringStyle
;
import
com.ruoyi.common.annotation.Excel
;
...
...
@@ -13,6 +14,7 @@ import com.ruoyi.common.core.domain.BaseEntity;
* @author ruoyi
* @date 2025-12-02
*/
@Data
public
class
InventoryTransactions
extends
BaseEntity
{
private
static
final
long
serialVersionUID
=
1L
;
...
...
@@ -91,218 +93,7 @@ public class InventoryTransactions extends BaseEntity
@Excel
(
name
=
"排序号"
)
private
String
updateUserCode
;
public
String
getInventoryId
()
{
return
inventoryId
;
}
@Excel
(
name
=
"单价"
)
private
String
unitPrice
;
public
void
setInventoryId
(
String
inventoryId
)
{
this
.
inventoryId
=
inventoryId
;
}
public
void
setId
(
String
id
)
{
this
.
id
=
id
;
}
public
String
getId
()
{
return
id
;
}
public
void
setTransactionType
(
Long
transactionType
)
{
this
.
transactionType
=
transactionType
;
}
public
Long
getTransactionType
()
{
return
transactionType
;
}
public
void
setReferenceId
(
String
referenceId
)
{
this
.
referenceId
=
referenceId
;
}
public
String
getReferenceId
()
{
return
referenceId
;
}
public
void
setReferenceItemId
(
String
referenceItemId
)
{
this
.
referenceItemId
=
referenceItemId
;
}
public
String
getReferenceItemId
()
{
return
referenceItemId
;
}
public
void
setMaterialId
(
String
materialId
)
{
this
.
materialId
=
materialId
;
}
public
String
getMaterialId
()
{
return
materialId
;
}
public
void
setBatchCode
(
String
batchCode
)
{
this
.
batchCode
=
batchCode
;
}
public
String
getBatchCode
()
{
return
batchCode
;
}
public
void
setWarehouseId
(
String
warehouseId
)
{
this
.
warehouseId
=
warehouseId
;
}
public
String
getWarehouseId
()
{
return
warehouseId
;
}
public
void
setLocationId
(
String
locationId
)
{
this
.
locationId
=
locationId
;
}
public
String
getLocationId
()
{
return
locationId
;
}
public
void
setOwnerId
(
String
ownerId
)
{
this
.
ownerId
=
ownerId
;
}
public
String
getOwnerId
()
{
return
ownerId
;
}
public
void
setQuantityBefore
(
Long
quantityBefore
)
{
this
.
quantityBefore
=
quantityBefore
;
}
public
Long
getQuantityBefore
()
{
return
quantityBefore
;
}
public
void
setQuantityChange
(
Long
quantityChange
)
{
this
.
quantityChange
=
quantityChange
;
}
public
Long
getQuantityChange
()
{
return
quantityChange
;
}
public
void
setQuantityAfter
(
Long
quantityAfter
)
{
this
.
quantityAfter
=
quantityAfter
;
}
public
Long
getQuantityAfter
()
{
return
quantityAfter
;
}
public
void
setTransactionTime
(
Date
transactionTime
)
{
this
.
transactionTime
=
transactionTime
;
}
public
Date
getTransactionTime
()
{
return
transactionTime
;
}
public
void
setOperatedBy
(
String
operatedBy
)
{
this
.
operatedBy
=
operatedBy
;
}
public
String
getOperatedBy
()
{
return
operatedBy
;
}
public
void
setIsUsed
(
Long
isUsed
)
{
this
.
isUsed
=
isUsed
;
}
public
Long
getIsUsed
()
{
return
isUsed
;
}
public
void
setSortNo
(
Long
sortNo
)
{
this
.
sortNo
=
sortNo
;
}
public
Long
getSortNo
()
{
return
sortNo
;
}
public
void
setCreateUserCode
(
String
createUserCode
)
{
this
.
createUserCode
=
createUserCode
;
}
public
String
getCreateUserCode
()
{
return
createUserCode
;
}
public
void
setUpdateUserCode
(
String
updateUserCode
)
{
this
.
updateUserCode
=
updateUserCode
;
}
public
String
getUpdateUserCode
()
{
return
updateUserCode
;
}
@Override
public
String
toString
()
{
return
new
ToStringBuilder
(
this
,
ToStringStyle
.
MULTI_LINE_STYLE
)
.
append
(
"id"
,
getId
())
.
append
(
"transactionType"
,
getTransactionType
())
.
append
(
"referenceId"
,
getReferenceId
())
.
append
(
"referenceItemId"
,
getReferenceItemId
())
.
append
(
"materialId"
,
getMaterialId
())
.
append
(
"batchCode"
,
getBatchCode
())
.
append
(
"warehouseId"
,
getWarehouseId
())
.
append
(
"locationId"
,
getLocationId
())
.
append
(
"ownerId"
,
getOwnerId
())
.
append
(
"quantityBefore"
,
getQuantityBefore
())
.
append
(
"quantityChange"
,
getQuantityChange
())
.
append
(
"quantityAfter"
,
getQuantityAfter
())
.
append
(
"transactionTime"
,
getTransactionTime
())
.
append
(
"operatedBy"
,
getOperatedBy
())
.
append
(
"remark"
,
getRemark
())
.
append
(
"isUsed"
,
getIsUsed
())
.
append
(
"sortNo"
,
getSortNo
())
.
append
(
"createTime"
,
getCreateTime
())
.
append
(
"createUserCode"
,
getCreateUserCode
())
.
append
(
"updateTime"
,
getUpdateTime
())
.
append
(
"updateUserCode"
,
getUpdateUserCode
())
.
toString
();
}
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/OutboundOrderItems.java
View file @
db0c0a3a
...
...
@@ -66,7 +66,7 @@ public class OutboundOrderItems extends BaseEntity
/** 单价 */
@Excel
(
name
=
"单价"
)
private
Long
unitPrice
;
private
Double
unitPrice
;
/** 计划数量 */
@Excel
(
name
=
"计划数量"
)
...
...
@@ -117,5 +117,7 @@ public class OutboundOrderItems extends BaseEntity
@Excel
(
name
=
"排序号"
)
private
String
updateUserCode
;
private
String
InventoryType
;
}
\ No newline at end of file
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/Owners.java
View file @
db0c0a3a
...
...
@@ -28,7 +28,7 @@ public class Owners extends BaseEntity
@Excel
(
name
=
"货主名称"
)
private
String
ownerName
;
@Excel
(
name
=
"
货主
名称"
)
@Excel
(
name
=
"
英文
名称"
)
private
String
englishName
;
/** 货主类型 1-供应商 2-客户 3-内部 检索条件 */
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/InboundTemplateVO.java
deleted
100644 → 0
View file @
6eab21f8
package
com
.
ruoyi
.
inventory
.
domain
.
vo
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
com.ruoyi.common.annotation.Excel
;
import
com.ruoyi.common.core.domain.BaseEntity
;
import
java.util.Date
;
/**
* 入库单导入对象 inboundTemplate
*
* @author ruoyi
* @date 2025-12-02
*/
public
class
InboundTemplateVO
extends
BaseEntity
{
private
static
final
long
serialVersionUID
=
1L
;
/** 编号 */
private
String
id
;
/** 入库日期 日期无时间 */
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
)
@Excel
(
name
=
"入库日期"
,
width
=
30
,
dateFormat
=
"yyyy-MM-dd"
)
private
Date
inboundDate
;
/** 货物ID 字典,检索条件 */
@Excel
(
name
=
"SAP No"
)
private
String
sapNo
;
/** 货物名称 */
@Excel
(
name
=
"物料名称"
)
private
String
materialName
;
/** 货物名称 */
@Excel
(
name
=
"TS Code"
)
private
String
tsCode
;
/** 货主ID */
@Excel
(
name
=
"货主"
)
private
String
ownerId
;
/** 批次ID 检索条件 */
@Excel
(
name
=
"批号"
)
private
String
batchId
;
/** 计划数量 */
@Excel
(
name
=
"计划数量"
)
private
Long
plannedQuantity
;
/** 入库单号 检索条件 */
@Excel
(
name
=
"单号"
)
private
String
orderId
;
/** 系统编号 检索条件 */
@Excel
(
name
=
"系统编号"
)
private
String
systemNo
;
/** 入库类型 字典,检索条件 */
// @Excel(name = "入库类型")
private
String
orderTypeId
;
@Excel
(
name
=
"件重"
)
private
Double
unitWeight
;
/** 约数 */
@Excel
(
name
=
"约数"
)
private
Long
divisor
;
/** 实际件数 */
@Excel
(
name
=
"实际件数"
)
private
Long
actualPackages
;
/** 实际数量 */
@Excel
(
name
=
"实发数量"
)
private
Long
actualQuantity
;
/** 仓库ID 暂无用 */
@Excel
(
name
=
"仓库"
)
private
String
warehouseId
;
/** 库位ID 检索条件 */
@Excel
(
name
=
"库位"
)
private
String
locationId
;
/** 标签颜色 字典,检索条件 */
@Excel
(
name
=
"标签颜色"
)
private
Long
labelColor
;
/** 凭证号 检索条件 */
@Excel
(
name
=
"凭证号"
)
private
String
voucherNumber
;
/** 单价 */
@Excel
(
name
=
"单价"
)
private
Long
unitPrice
;
/** 备注 */
@Excel
(
name
=
"备注"
)
private
String
remark
;
/** 订单类型 字典,检索条件 */
@Excel
(
name
=
"订单类型"
)
private
String
orderType
;
/** 收货人 */
@Excel
(
name
=
"收货人"
)
private
String
receivedBy
;
/** 物料备注 */
@Excel
(
name
=
"物料备注"
)
private
String
remark2
;
/** 负责人 暂无用 */
// @Excel(name = "负责人 暂无用")
private
String
opUserName
;
/** 计划件数 暂无用 */
// @Excel(name = "件数")
private
Long
plannedPackages
;
/** 排序号 */
private
Long
sortNo
;
/** 创建日期 */
private
String
createUserCode
;
private
String
updateUserCode
;
public
String
getId
()
{
return
id
;
}
public
void
setId
(
String
id
)
{
this
.
id
=
id
;
}
public
String
getOrderId
()
{
return
orderId
;
}
public
void
setOrderId
(
String
orderId
)
{
this
.
orderId
=
orderId
;
}
public
String
getSystemNo
()
{
return
systemNo
;
}
public
void
setSystemNo
(
String
systemNo
)
{
this
.
systemNo
=
systemNo
;
}
public
String
getOrderTypeId
()
{
return
orderTypeId
;
}
public
void
setOrderTypeId
(
String
orderTypeId
)
{
this
.
orderTypeId
=
orderTypeId
;
}
public
String
getBatchId
()
{
return
batchId
;
}
public
void
setBatchId
(
String
batchId
)
{
this
.
batchId
=
batchId
;
}
public
Date
getInboundDate
()
{
return
inboundDate
;
}
public
void
setInboundDate
(
Date
inboundDate
)
{
this
.
inboundDate
=
inboundDate
;
}
public
String
getOrderType
()
{
return
orderType
;
}
public
void
setOrderType
(
String
orderType
)
{
this
.
orderType
=
orderType
;
}
public
String
getRemark
()
{
return
remark
;
}
public
void
setRemark
(
String
remark
)
{
this
.
remark
=
remark
;
}
public
String
getOwnerId
()
{
return
ownerId
;
}
public
void
setOwnerId
(
String
ownerId
)
{
this
.
ownerId
=
ownerId
;
}
public
String
getWarehouseId
()
{
return
warehouseId
;
}
public
void
setWarehouseId
(
String
warehouseId
)
{
this
.
warehouseId
=
warehouseId
;
}
public
String
getLocationId
()
{
return
locationId
;
}
public
void
setLocationId
(
String
locationId
)
{
this
.
locationId
=
locationId
;
}
public
String
getRemark2
()
{
return
remark2
;
}
public
void
setRemark2
(
String
remark2
)
{
this
.
remark2
=
remark2
;
}
public
String
getSapNo
()
{
return
sapNo
;
}
public
void
setSapNo
(
String
sapNo
)
{
this
.
sapNo
=
sapNo
;
}
public
String
getMaterialName
()
{
return
materialName
;
}
public
void
setMaterialName
(
String
materialName
)
{
this
.
materialName
=
materialName
;
}
public
String
getOpUserName
()
{
return
opUserName
;
}
public
void
setOpUserName
(
String
opUserName
)
{
this
.
opUserName
=
opUserName
;
}
public
Long
getPlannedQuantity
()
{
return
plannedQuantity
;
}
public
void
setPlannedQuantity
(
Long
plannedQuantity
)
{
this
.
plannedQuantity
=
plannedQuantity
;
}
public
Long
getActualQuantity
()
{
return
actualQuantity
;
}
public
void
setActualQuantity
(
Long
actualQuantity
)
{
this
.
actualQuantity
=
actualQuantity
;
}
public
Long
getPlannedPackages
()
{
return
plannedPackages
;
}
public
void
setPlannedPackages
(
Long
plannedPackages
)
{
this
.
plannedPackages
=
plannedPackages
;
}
public
Long
getActualPackages
()
{
return
actualPackages
;
}
public
void
setActualPackages
(
Long
actualPackages
)
{
this
.
actualPackages
=
actualPackages
;
}
public
Long
getDivisor
()
{
return
divisor
;
}
public
void
setDivisor
(
Long
divisor
)
{
this
.
divisor
=
divisor
;
}
public
Long
getLabelColor
()
{
return
labelColor
;
}
public
void
setLabelColor
(
Long
labelColor
)
{
this
.
labelColor
=
labelColor
;
}
public
String
getVoucherNumber
()
{
return
voucherNumber
;
}
public
void
setVoucherNumber
(
String
voucherNumber
)
{
this
.
voucherNumber
=
voucherNumber
;
}
public
Long
getUnitPrice
()
{
return
unitPrice
;
}
public
void
setUnitPrice
(
Long
unitPrice
)
{
this
.
unitPrice
=
unitPrice
;
}
public
String
getReceivedBy
()
{
return
receivedBy
;
}
public
void
setReceivedBy
(
String
receivedBy
)
{
this
.
receivedBy
=
receivedBy
;
}
public
String
getCreateUserCode
()
{
return
createUserCode
;
}
public
void
setCreateUserCode
(
String
createUserCode
)
{
this
.
createUserCode
=
createUserCode
;
}
public
String
getUpdateUserCode
()
{
return
updateUserCode
;
}
public
void
setUpdateUserCode
(
String
updateUserCode
)
{
this
.
updateUserCode
=
updateUserCode
;
}
public
Long
getSortNo
()
{
return
sortNo
;
}
public
void
setSortNo
(
Long
sortNo
)
{
this
.
sortNo
=
sortNo
;
}
public
String
getTsCode
()
{
return
tsCode
;
}
public
void
setTsCode
(
String
tsCode
)
{
this
.
tsCode
=
tsCode
;
}
public
Double
getUnitWeight
()
{
return
unitWeight
;
}
public
void
setUnitWeight
(
Double
unitWeight
)
{
this
.
unitWeight
=
unitWeight
;
}
@Override
public
String
toString
()
{
return
"InboundTemplateVO{"
+
"id='"
+
id
+
'\''
+
", inboundDate="
+
inboundDate
+
", sapNo='"
+
sapNo
+
'\''
+
", materialName='"
+
materialName
+
'\''
+
", tsCode='"
+
tsCode
+
'\''
+
", batchId='"
+
batchId
+
'\''
+
", plannedQuantity="
+
plannedQuantity
+
", orderId='"
+
orderId
+
'\''
+
", systemNo='"
+
systemNo
+
'\''
+
", orderTypeId='"
+
orderTypeId
+
'\''
+
", unitWeight="
+
unitWeight
+
", divisor="
+
divisor
+
", actualPackages="
+
actualPackages
+
", actualQuantity="
+
actualQuantity
+
", warehouseId='"
+
warehouseId
+
'\''
+
", locationId='"
+
locationId
+
'\''
+
", labelColor="
+
labelColor
+
", voucherNumber='"
+
voucherNumber
+
'\''
+
", unitPrice="
+
unitPrice
+
", remark='"
+
remark
+
'\''
+
", orderType='"
+
orderType
+
'\''
+
", receivedBy='"
+
receivedBy
+
'\''
+
", remark2='"
+
remark2
+
'\''
+
", ownerId='"
+
ownerId
+
'\''
+
", opUserName='"
+
opUserName
+
'\''
+
", plannedPackages="
+
plannedPackages
+
", sortNo="
+
sortNo
+
", createUserCode='"
+
createUserCode
+
'\''
+
", updateUserCode='"
+
updateUserCode
+
'\''
+
'}'
;
}
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/inboundVO/InboundFinishTemplateVO.java
0 → 100644
View file @
db0c0a3a
package
com
.
ruoyi
.
inventory
.
domain
.
vo
.
inboundVO
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
com.ruoyi.common.annotation.Excel
;
import
com.ruoyi.common.core.domain.BaseEntity
;
import
lombok.Data
;
import
java.util.Date
;
@Data
public
class
InboundFinishTemplateVO
extends
BaseEntity
{
private
static
final
long
serialVersionUID
=
1L
;
/** 编号 */
private
String
id
;
/** 入库日期 日期无时间 */
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
)
@Excel
(
name
=
"日期"
,
width
=
30
,
dateFormat
=
"yyyy-MM-dd"
)
private
Date
inboundDate
;
/** 货物ID 字典,检索条件 */
@Excel
(
name
=
"SAP No"
)
private
String
sapNo
;
/** 货物名称 */
@Excel
(
name
=
"物料名称"
)
private
String
materialName
;
/** 货物名称 */
@Excel
(
name
=
"TS Code"
)
private
String
tsCode
;
/** 批次ID 检索条件 */
@Excel
(
name
=
"批号"
)
private
String
batchId
;
/** 计划数量 */
@Excel
(
name
=
"计划数量"
)
private
Long
plannedQuantity
;
@Excel
(
name
=
"件重"
)
private
Double
packageWeight
;
/** 约数 */
@Excel
(
name
=
"约数"
)
private
Long
divisor
;
@Excel
(
name
=
"件数"
)
private
Long
actualPackages
;
@Excel
(
name
=
"重量"
)
private
Double
unitWeight
;
/** 实际数量 */
// @Excel(name = "实发数量")
private
Long
actualQuantity
;
/** 库位 */
@Excel
(
name
=
"库位"
)
private
String
locationId
;
/** 仓库ID 暂无用 */
@Excel
(
name
=
"仓库"
)
private
String
warehouseId
;
/** 成品表里的第二个 "库位" */
@Excel
(
name
=
"库位"
)
private
String
remark2
;
/** 库位ID 检索条件 */
// @Excel(name = "收货库位")
private
String
relocationId
;
/** 标签颜色 字典,检索条件 */
@Excel
(
name
=
"标签颜色"
)
private
Long
labelColor
;
/** 凭证号 检索条件 */
@Excel
(
name
=
"凭证号"
)
private
String
voucherNumber
;
@Excel
(
name
=
"保温"
)
private
String
keepWarm
;
@Excel
(
name
=
"危险类别"
)
private
String
hazardId
;
/** 入库单号 检索条件 */
@Excel
(
name
=
"智观(客户订单号)"
)
private
String
orderId
;
/** 系统编号 检索条件 */
@Excel
(
name
=
"客户订单号/PO号"
)
private
String
systemNo
;
/** 货主ID */
@Excel
(
name
=
"货主"
)
private
String
ownerId
;
/** 入库类型 字典,检索条件 */
@Excel
(
name
=
"贴标数量"
)
private
String
labelQuantity
;
/** 订单类型 字典,检索条件 */
@Excel
(
name
=
"订单类型"
)
private
String
orderType
;
@Excel
(
name
=
"单个件重"
)
private
Double
packageWeight2
;
/** 单价 */
// @Excel(name = "单价")
private
Long
unitPrice
;
/** 收货人 */
// @Excel(name = "收货人")
private
String
receivedBy
;
/** 物料备注 */
// @Excel(name = "物料备注")
private
String
remark1
;
/** 负责人 暂无用 */
// @Excel(name = "负责人 暂无用")
private
String
opUserName
;
/** 计划件数 暂无用 */
// @Excel(name = "件数")
private
Long
plannedPackages
;
/** 排序号 */
private
Long
sortNo
;
/** 创建日期 */
private
String
createUserCode
;
private
String
updateUserCode
;
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/inboundVO/InboundTRDCTemplateVO.java
0 → 100644
View file @
db0c0a3a
package
com
.
ruoyi
.
inventory
.
domain
.
vo
.
inboundVO
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
com.ruoyi.common.annotation.Excel
;
import
com.ruoyi.common.core.domain.BaseEntity
;
import
lombok.Data
;
import
java.util.Date
;
@Data
public
class
InboundTRDCTemplateVO
extends
BaseEntity
{
private
static
final
long
serialVersionUID
=
1L
;
/** 编号 */
private
String
id
;
/** 入库日期 日期无时间 */
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
)
@Excel
(
name
=
"日期"
,
width
=
30
,
dateFormat
=
"yyyy-MM-dd"
)
private
Date
inboundDate
;
/** 货物ID 字典,检索条件 */
@Excel
(
name
=
"SAP No"
)
private
String
sapNo
;
/** 货物名称 */
@Excel
(
name
=
"物料名称"
)
private
String
materialName
;
/** 货物名称 */
@Excel
(
name
=
"TS Code"
)
private
String
tsCode
;
/** 批次ID 检索条件 */
@Excel
(
name
=
"批号"
)
private
String
batchId
;
/** 计划数量 */
@Excel
(
name
=
"计划数量"
)
private
Long
plannedQuantity
;
@Excel
(
name
=
"件重"
)
private
Double
unitWeight
;
/** 约数 */
@Excel
(
name
=
"约数"
)
private
Long
divisor
;
/** 实际件数 */
@Excel
(
name
=
"件数"
)
private
Long
actualPackages
;
/** 实际数量 */
@Excel
(
name
=
"实发数量"
)
private
Long
actualQuantity
;
/** 库位ID 检索条件 */
@Excel
(
name
=
"库位"
)
private
String
locationId
;
/** 仓库ID 暂无用 */
@Excel
(
name
=
"仓库"
)
private
String
warehouseId
;
/** 备注 */
@Excel
(
name
=
"备注"
)
private
String
remark
;
/** 库位ID 检索条件 */
// @Excel(name = "收货库位")
private
String
relocationId
;
/** 标签颜色 字典,检索条件 */
@Excel
(
name
=
"标签颜色"
)
private
Long
labelColor
;
/** 凭证号 检索条件 */
@Excel
(
name
=
"凭证号"
)
private
String
voucherNumber
;
@Excel
(
name
=
"保温"
)
private
String
keepWarm
;
@Excel
(
name
=
"危险类别"
)
private
String
hazardId
;
/** 入库单号 检索条件 */
@Excel
(
name
=
"单号"
)
private
String
orderId
;
/** 系统编号 检索条件 */
@Excel
(
name
=
"系统编号"
)
private
String
systemNo
;
/** 货主ID */
@Excel
(
name
=
"货主"
)
private
String
ownerId
;
/** 入库类型 字典,检索条件 */
@Excel
(
name
=
"贴标数量"
)
private
String
labelQuantity
;
/** 订单类型 字典,检索条件 */
@Excel
(
name
=
"订单类型"
)
private
String
orderType
;
@Excel
(
name
=
"单件重量"
)
private
Double
packageWeight
;
/** 单价 */
// @Excel(name = "单价")
private
Long
unitPrice
;
/** 收货人 */
// @Excel(name = "收货人")
private
String
receivedBy
;
/** 物料备注 */
// @Excel(name = "物料备注")
private
String
remark2
;
/** 负责人 暂无用 */
// @Excel(name = "负责人 暂无用")
private
String
opUserName
;
/** 计划件数 暂无用 */
// @Excel(name = "件数")
private
Long
plannedPackages
;
/** 排序号 */
private
Long
sortNo
;
/** 创建日期 */
private
String
createUserCode
;
private
String
updateUserCode
;
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/domain/vo/inboundVO/InboundTemplateVO.java
0 → 100644
View file @
db0c0a3a
package
com
.
ruoyi
.
inventory
.
domain
.
vo
.
inboundVO
;
import
com.fasterxml.jackson.annotation.JsonFormat
;
import
com.ruoyi.common.annotation.Excel
;
import
com.ruoyi.common.core.domain.BaseEntity
;
import
lombok.Data
;
import
java.util.Date
;
/**
* 入库单导入对象 inboundTemplate
*
* @author ZTW
* @date 2025-12-02
*/
@Data
public
class
InboundTemplateVO
extends
BaseEntity
{
private
static
final
long
serialVersionUID
=
1L
;
/** 编号 */
private
String
id
;
/** 入库日期 日期无时间 */
@JsonFormat
(
pattern
=
"yyyy-MM-dd"
)
@Excel
(
name
=
"日期"
,
width
=
30
,
dateFormat
=
"yyyy-MM-dd"
)
private
Date
inboundDate
;
/** 货物ID 字典,检索条件 */
@Excel
(
name
=
"SAP No"
)
private
String
sapNo
;
/** 货物名称 */
@Excel
(
name
=
"物料名称"
)
private
String
materialName
;
/** 货物名称 */
@Excel
(
name
=
"TS Code"
)
private
String
tsCode
;
/** 批次ID 检索条件 */
@Excel
(
name
=
"批号"
)
private
String
batchId
;
/** 计划数量 */
@Excel
(
name
=
"计划数量"
)
private
Long
plannedQuantity
;
@Excel
(
name
=
"件重"
)
private
Double
unitWeight
;
/** 约数 */
@Excel
(
name
=
"约数"
)
private
Long
divisor
;
/** 实际件数 */
@Excel
(
name
=
"件数"
)
private
Long
actualPackages
;
/** 实际数量 */
@Excel
(
name
=
"实发数量"
)
private
Long
actualQuantity
;
/** 库位ID 检索条件 */
@Excel
(
name
=
"库位"
)
private
String
locationId
;
/** 仓库ID 暂无用 */
@Excel
(
name
=
"仓库"
)
private
String
warehouseId
;
/** 备注 */
// @Excel(name = "备注")
private
String
remark
;
/** 库位ID 检索条件 */
@Excel
(
name
=
"收货库位"
)
private
String
relocationId
;
/** 标签颜色 字典,检索条件 */
@Excel
(
name
=
"标签颜色"
)
private
Long
labelColor
;
/** 凭证号 检索条件 */
@Excel
(
name
=
"凭证号"
)
private
String
voucherNumber
;
@Excel
(
name
=
"保温"
)
private
String
keepWarm
;
@Excel
(
name
=
"危险类别"
)
private
String
hazardId
;
/** 入库单号 检索条件 */
@Excel
(
name
=
"单号"
)
private
String
orderId
;
/** 系统编号 检索条件 */
@Excel
(
name
=
"系统编号"
)
private
String
systemNo
;
/** 货主ID */
@Excel
(
name
=
"货主"
)
private
String
ownerId
;
/** 入库类型 字典,检索条件 */
@Excel
(
name
=
"贴标数量"
)
private
String
labelQuantity
;
/** 订单类型 字典,检索条件 */
@Excel
(
name
=
"订单类型"
)
private
String
orderType
;
@Excel
(
name
=
"单件重量"
)
private
Double
packageWeight
;
/** 单价 */
// @Excel(name = "单价")
private
Long
unitPrice
;
/** 收货人 */
// @Excel(name = "收货人")
private
String
receivedBy
;
/** 物料备注 */
// @Excel(name = "物料备注")
private
String
remark2
;
/** 负责人 暂无用 */
// @Excel(name = "负责人 暂无用")
private
String
opUserName
;
/** 计划件数 暂无用 */
// @Excel(name = "件数")
private
Long
plannedPackages
;
/** 排序号 */
private
Long
sortNo
;
/** 创建日期 */
private
String
createUserCode
;
private
String
updateUserCode
;
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/mapper/InventoryMapper.java
View file @
db0c0a3a
...
...
@@ -116,4 +116,6 @@ public interface InventoryMapper
public
List
<
java
.
util
.
Map
<
String
,
String
>>
selectInventoryTopTenByAmount
();
public
List
<
java
.
util
.
Map
<
String
,
String
>>
selectInventoryTopTenByQuantity
();
public
void
batchUpdateInventory
(
List
<
Inventory
>
inventoryList
);
}
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/IInboundOrdersService.java
View file @
db0c0a3a
...
...
@@ -2,10 +2,9 @@ package com.ruoyi.inventory.service;
import
java.util.List
;
import
com.ruoyi.inventory.domain.InboundOrderItems
;
import
com.ruoyi.inventory.domain.InboundOrders
;
import
com.ruoyi.inventory.domain.vo.InboundMaterialTotalVO
;
import
com.ruoyi.inventory.domain.vo.InboundTemplateVO
;
/**
* 入库单主Service接口
...
...
@@ -69,7 +68,7 @@ public interface IInboundOrdersService
* @param inboundOrders,isUpdateSupport,operName 入库单数据信息
* @return 结果
*/
public
String
importInboundOrders
(
List
<
InboundTemplateVO
>
inboundOrders
,
Integer
isUpdateSupport
,
String
operName
,
Integer
orderType
);
public
<
T
>
String
importInboundOrders
(
List
<
T
>
inboundOrders
,
Integer
isUpdateSupport
,
String
operName
,
Integer
orderType
);
/**
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/IOutboundOrderItemsService.java
View file @
db0c0a3a
...
...
@@ -2,10 +2,7 @@ package com.ruoyi.inventory.service;
import
java.util.List
;
import
com.ruoyi.inventory.domain.OutboundOrderItems
;
import
com.ruoyi.inventory.domain.vo.InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.OutboundOrdersSummaryVO
;
import
com.ruoyi.inventory.domain.vo.OutboundTemplateVO
;
import
org.springframework.transaction.annotation.Transactional
;
/**
* 出库单明细Service接口
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/InboundOrdersServiceImpl.java
View file @
db0c0a3a
package
com
.
ruoyi
.
inventory
.
service
.
impl
;
import
java.lang.reflect.Method
;
import
java.time.LocalDate
;
import
java.time.format.DateTimeFormatter
;
import
java.util.*
;
import
java.util.stream.Collectors
;
import
com.ruoyi.common.config.WarehouseConfig
;
import
com.ruoyi.common.exception.ServiceException
;
import
com.ruoyi.inventory.domain.*
;
import
com.ruoyi.inventory.domain.vo.InboundMaterialTotalVO
;
import
com.ruoyi.inventory.mapper.*
;
import
org.apache.commons.lang3.SystemUtils
;
import
org.springframework.transaction.interceptor.TransactionAspectSupport
;
import
org.springframework.util.CollectionUtils
;
import
com.ruoyi.common.exception.ServiceException
;
import
com.ruoyi.common.utils.DateUtils
;
import
com.ruoyi.common.utils.SecurityUtils
;
import
com.ruoyi.common.utils.bean.BeanUtils
;
import
com.ruoyi.inventory.domain.vo.InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.
inboundVO.
InboundTemplateVO
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
@@ -27,12 +30,12 @@ import com.ruoyi.inventory.service.IInboundOrdersService;
/**
* 入库单主Service业务层处理
*
*
* @author ruoyi
* @date 2025-12-02
*/
@Service
public
class
InboundOrdersServiceImpl
implements
IInboundOrdersService
public
class
InboundOrdersServiceImpl
implements
IInboundOrdersService
{
@Autowired
private
InboundOrdersMapper
inboundOrdersMapper
;
...
...
@@ -49,7 +52,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
private
static
final
Logger
log
=
LoggerFactory
.
getLogger
(
InboundOrdersServiceImpl
.
class
);
/**
* 查询入库单主
*
*
* @param id 入库单主主键
* @return 入库单主
*/
...
...
@@ -61,7 +64,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
/**
* 查询入库单主列表
*
*
* @param inboundOrders 入库单主
* @return 入库单主
*/
...
...
@@ -73,7 +76,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
/**
* 新增入库单主
*
*
* @param inboundOrders 入库单主
* @return 结果
*/
...
...
@@ -91,7 +94,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
/**
* 修改入库单主
*
*
* @param inboundOrders 入库单主
* @return 结果
*/
...
...
@@ -109,7 +112,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
/**
* 批量删除入库单主
*
*
* @param ids 需要删除的入库单主主键
* @return 结果
*/
...
...
@@ -123,7 +126,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
/**
* 删除入库单主信息
*
*
* @param id 入库单主主键
* @return 结果
*/
...
...
@@ -137,7 +140,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
/**
* 新增入库单明细信息
*
*
* @param inboundOrders 入库单主对象
*/
public
void
insertInboundOrderItems
(
InboundOrders
inboundOrders
)
...
...
@@ -174,7 +177,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
*/
@Override
@Transactional
(
rollbackFor
=
Exception
.
class
)
public
String
importInboundOrders
(
List
<
InboundTemplateVO
>
inboundOrdersList
,
Integer
isUpdateSupport
,
String
operName
,
Integer
orderType
)
{
public
<
T
>
String
importInboundOrders
(
List
<
T
>
inboundOrdersList
,
Integer
isUpdateSupport
,
String
operName
,
Integer
orderType
)
{
if
(
StringUtils
.
isNull
(
inboundOrdersList
)
||
inboundOrdersList
.
size
()
==
0
)
{
throw
new
ServiceException
(
"导入数据不能为空!"
);
}
...
...
@@ -196,22 +199,53 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
Map
<
String
,
String
>
warehouseNameIdMap
=
loadWarehouseNameIdMap
();
// 预加载库位名称-ID映射
Map
<
String
,
String
>
storageLocationNameIdMap
=
loadStorageLocationNameIdMap
();
// 3. 按入库单号分组(核心:同一入库单的多条明细归为一组)
Map
<
String
,
List
<
InboundTemplateVO
>>
orderGroupMap
=
Optional
.
ofNullable
(
inboundOrdersList
)
// 3. 按入库单号分组(核心:通过反射处理泛型T的orderId字段)
Map
<
String
,
List
<
T
>>
orderGroupMap
=
Optional
.
ofNullable
(
inboundOrdersList
)
.
orElse
(
Collections
.
emptyList
())
// 空列表兜底,避免NPE
.
stream
()
.
filter
(
Objects:
:
nonNull
)
// 过滤null的VO对象
.
map
(
vo
->
{
// 预处理:入库单号去空格,统一格式
String
orderId
=
Optional
.
ofNullable
(
vo
.
getOrderId
())
.
map
(
String:
:
trim
)
// 去除首尾空格
.
orElse
(
""
);
vo
.
setOrderId
(
orderId
);
// 把处理后的单号回写,保证后续使用一致
// 预处理:入库单号去空格,统一格式(反射调用get/setOrderId)
try
{
// 反射获取getOrderId方法
Method
getOrderIdMethod
=
vo
.
getClass
().
getMethod
(
"getOrderId"
);
String
orderId
=
Optional
.
ofNullable
(
getOrderIdMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
map
(
String:
:
trim
)
// 去除首尾空格
.
orElse
(
""
);
// 反射调用setOrderId方法回写处理后的单号
Method
setOrderIdMethod
=
vo
.
getClass
().
getMethod
(
"setOrderId"
,
String
.
class
);
setOrderIdMethod
.
invoke
(
vo
,
orderId
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"实体类缺少orderId的getter/setter方法"
+
e
);
}
return
vo
;
})
.
filter
(
vo
->
StringUtils
.
isNotBlank
(
vo
.
getOrderId
()))
// 过滤无/空白入库单号的无效行
.
filter
(
vo
->
{
// 反射过滤无/空白入库单号的无效行
try
{
Method
getOrderIdMethod
=
vo
.
getClass
().
getMethod
(
"getOrderId"
);
String
orderId
=
Optional
.
ofNullable
(
getOrderIdMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
orElse
(
""
);
return
StringUtils
.
isNotBlank
(
orderId
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"获取orderId失败"
+
e
);
}
})
.
collect
(
Collectors
.
groupingBy
(
InboundTemplateVO:
:
getOrderId
,
// 分组Key:处理后的入库单号
vo
->
{
// 反射获取分组Key:处理后的入库单号
try
{
Method
getOrderIdMethod
=
vo
.
getClass
().
getMethod
(
"getOrderId"
);
return
Optional
.
ofNullable
(
getOrderIdMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
orElse
(
""
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"分组获取orderId失败"
+
e
);
}
},
Collectors
.
collectingAndThen
(
Collectors
.
toList
(),
list
->
Collections
.
unmodifiableList
(
list
)
// 生成不可变列表,防止后续篡改
...
...
@@ -219,16 +253,17 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
));
// 兜底:若分组结果为空,返回空的不可变Map(避免后续判空)
orderGroupMap
=
Optional
.
ofNullable
(
orderGroupMap
).
orElse
(
Collections
.
emptyMap
());
// 4. 遍历每个入库单分组处理
for
(
Map
.
Entry
<
String
,
List
<
InboundTemplateVO
>>
entry
:
orderGroupMap
.
entrySet
())
{
for
(
Map
.
Entry
<
String
,
List
<
T
>>
entry
:
orderGroupMap
.
entrySet
())
{
String
orderId
=
entry
.
getKey
();
List
<
InboundTemplateVO
>
voList
=
entry
.
getValue
();
List
<
T
>
voList
=
entry
.
getValue
();
InboundOrders
mainDO
=
null
;
List
<
InboundOrderItems
>
itemDOList
=
new
ArrayList
<>();
try
{
// 4.1 处理主表(每个入库单号只处理一次主表)
InboundTemplateVO
firstVO
=
voList
.
get
(
0
);
// 取第一条VO的主表信息
T
firstVO
=
voList
.
get
(
0
);
// 取第一条VO的主表信息
// 检查入库单是否已存在
InboundOrders
existMain
=
inboundOrdersMapper
.
selectInboundOrdersByOrderId
(
orderId
);
...
...
@@ -242,7 +277,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
}
// 支持更新,复用已有主表ID
mainDO
=
existMain
;
// 复制VO中的主表字段到已有主表(只更新可修改的字段)
//
反射
复制VO中的主表字段到已有主表(只更新可修改的字段)
BeanUtils
.
copyProperties
(
firstVO
,
mainDO
,
"id"
,
"createBy"
,
"createTime"
);
// 排除不可更新字段
mainDO
.
setUpdateBy
(
operId
);
mainDO
.
setUpdateTime
(
now
);
...
...
@@ -255,7 +290,7 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
}
else
{
// 新增主表
mainDO
=
new
InboundOrders
();
// 复制主表字段(只复制主表相关字段,避免物料字段污染)
//
反射
复制主表字段(只复制主表相关字段,避免物料字段污染)
BeanUtils
.
copyProperties
(
firstVO
,
mainDO
,
"sapNo"
,
"materialName"
,
"plannedQuantity"
,
"actualQuantity"
,
"plannedPackages"
,
"materialUnit"
,
"materialRemark"
);
// 排除子表字段
...
...
@@ -274,9 +309,18 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
mainDO
.
setOrderStatus
(
1L
);
// 默认草稿状态
}
// ========== 货主查询 ==========
// ========== 货主查询(反射获取ownerId) ==========
String
ownerName
=
""
;
try
{
Method
getOwnerIdMethod
=
firstVO
.
getClass
().
getMethod
(
"getOwnerId"
);
ownerName
=
Optional
.
ofNullable
(
getOwnerIdMethod
.
invoke
(
firstVO
))
.
map
(
Object:
:
toString
)
.
orElse
(
""
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"获取货主名称失败"
+
e
);
}
Owners
owners
=
new
Owners
();
owners
.
setOwnerName
(
mainDO
.
getOwnerId
()
);
owners
.
setOwnerName
(
ownerName
);
List
<
Owners
>
olist
=
ownersMapper
.
selectOwnersList
(
owners
);
if
(
CollectionUtils
.
isEmpty
(
olist
))
{
// 抛业务异常,携带具体单号/条件,方便排查
...
...
@@ -291,11 +335,10 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
}
// 4.2 处理子表明细(每条VO对应一条明细)
for
(
InboundTemplateVO
vo
:
voList
)
{
for
(
T
vo
:
voList
)
{
try
{
InboundOrderItems
itemDO
=
new
InboundOrderItems
();
// 复制子表字段(物料相关)
//
反射
复制子表字段(物料相关)
BeanUtils
.
copyProperties
(
vo
,
itemDO
,
"orderId"
,
"systemNo"
,
"orderTypeId"
,
"batchId"
);
// 排除主表字段
// 填充明细必填字段
...
...
@@ -304,13 +347,45 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
itemDO
.
setCreateTime
(
now
);
itemDO
.
setCreateUserCode
(
operId
);
itemDO
.
setOrderId
(
orderId
);
// 关联入库单号
itemDO
.
setBatchId
(
mainDO
.
getBatchId
());
// 反射获取batchId并设置
String
batchId
=
""
;
try
{
Method
getBatchIdMethod
=
vo
.
getClass
().
getMethod
(
"getBatchId"
);
batchId
=
Optional
.
ofNullable
(
getBatchIdMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
orElse
(
""
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"获取批号失败"
+
e
);
}
itemDO
.
setBatchId
(
batchId
);
itemDO
.
setInboundOrderId
(
mainDO
.
getId
());
// 关联主表ID(核心!)
itemDO
.
setSortNo
(
0L
);
itemDO
.
setRemark
(
vo
.
getRemark2
());
// ========== 物料SAPNO校验 ==========
String
sapNo
=
Optional
.
ofNullable
(
vo
.
getSapNo
()).
map
(
String:
:
trim
).
orElse
(
""
);
// 反射获取remark2并设置
String
remark2
=
""
;
try
{
Method
getRemark2Method
=
vo
.
getClass
().
getMethod
(
"getRemark2"
);
remark2
=
Optional
.
ofNullable
(
getRemark2Method
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
orElse
(
""
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"获取明细备注失败"
+
e
);
}
itemDO
.
setRemark
(
remark2
);
// ========== 物料SAPNO校验(反射获取sapNo) ==========
String
sapNo
=
""
;
try
{
Method
getSapNoMethod
=
vo
.
getClass
().
getMethod
(
"getSapNo"
);
sapNo
=
Optional
.
ofNullable
(
getSapNoMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
map
(
String:
:
trim
)
.
orElse
(
""
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"获取物料SAP号失败"
+
e
);
}
if
(
StringUtils
.
isBlank
(
sapNo
))
{
throw
new
ServiceException
(
"物料SAP号为空"
);
}
...
...
@@ -320,28 +395,60 @@ public class InboundOrdersServiceImpl implements IInboundOrdersService
}
itemDO
.
setMaterialId
(
sapAndId
.
get
(
"id"
));
// ========== 仓库/库位查询 ==========
String
warehouseName
=
Optional
.
ofNullable
(
itemDO
.
getWarehouseId
()).
map
(
String:
:
trim
).
orElse
(
""
);
// ========== 仓库/库位查询(反射获取) ==========
// 1. 仓库名称转ID
String
warehouseName
=
""
;
try
{
Method
getWarehouseIdMethod
=
vo
.
getClass
().
getMethod
(
"getWarehouseId"
);
warehouseName
=
Optional
.
ofNullable
(
getWarehouseIdMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
map
(
String:
:
trim
)
.
orElse
(
""
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"获取仓库名称失败"
+
e
);
}
String
warehouseId
=
warehouseNameIdMap
.
get
(
warehouseName
);
if
(
StringUtils
.
isBlank
(
warehouseId
))
{
throw
new
ServiceException
(
"仓库【"
+
warehouseName
+
"】不存在"
);
log
.
info
(
"仓库【"
+
warehouseName
+
"】不存在,可能暂无仓库或为成品入库,已使用默认仓库"
);
itemDO
.
setWarehouseId
(
WarehouseConfig
.
DEFAULT_WAREHOUSE_ID
);
}
else
{
itemDO
.
setWarehouseId
(
warehouseId
);
}
// 2. 库位名称转ID
String
locationName
=
""
;
try
{
Method
getLocationIdMethod
=
vo
.
getClass
().
getMethod
(
"getLocationId"
);
locationName
=
Optional
.
ofNullable
(
getLocationIdMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
map
(
String:
:
trim
)
.
orElse
(
""
);
}
catch
(
Exception
e
)
{
throw
new
ServiceException
(
"获取库位名称失败"
+
e
);
}
itemDO
.
setWarehouseId
(
warehouseId
);
String
locationName
=
Optional
.
ofNullable
(
itemDO
.
getLocationId
()).
map
(
String:
:
trim
).
orElse
(
""
);
String
locationId
=
storageLocationNameIdMap
.
get
(
locationName
);
if
(
StringUtils
.
isBlank
(
locationId
))
{
throw
new
ServiceException
(
"库位【"
+
locationName
+
"】不存在"
);
log
.
info
(
"库位【"
+
locationName
+
"】不存在,可能暂无库位或为成品入库"
);
}
else
{
itemDO
.
setLocationId
(
locationId
);
}
itemDO
.
setLocationId
(
locationId
);
itemDOList
.
add
(
itemDO
);
}
catch
(
Exception
e
)
{
// 单个明细失败:仅统计,不影响整单
totalItemFailure
++;
// 反射获取sapNo用于错误提示
String
sapNo
=
""
;
try
{
Method
getSapNoMethod
=
vo
.
getClass
().
getMethod
(
"getSapNo"
);
sapNo
=
Optional
.
ofNullable
(
getSapNoMethod
.
invoke
(
vo
))
.
map
(
Object:
:
toString
)
.
orElse
(
"未知"
);
}
catch
(
Exception
ex
)
{
sapNo
=
"未知"
;
}
failureMsg
.
append
(
String
.
format
(
"入库单号【%s】的物料明细【%s】处理失败:%s;\n"
,
orderId
,
vo
.
getSapNo
()
,
e
.
getMessage
()));
log
.
error
(
"导入明细失败-入库单【{}】-SAP【{}】"
,
orderId
,
vo
.
getSapNo
()
,
e
);
orderId
,
sapNo
,
e
.
getMessage
()));
log
.
error
(
"导入明细失败-入库单【{}】-SAP【{}】"
,
orderId
,
sapNo
,
e
);
}
}
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/InventoryServiceImpl.java
View file @
db0c0a3a
...
...
@@ -159,14 +159,16 @@ public class InventoryServiceImpl implements IInventoryService
// 库存操作表插入数据
InventoryTransactions
transactions
=
new
InventoryTransactions
();
transactions
.
setId
(
IdUtils
.
simpleUUID
());
transactions
.
setTransactionType
(
2L
);
// 事务类型-盘点
transactions
.
setTransactionType
(
2L
);
// 事务类型-出库
transactions
.
setBatchCode
(
outboundOrderItem
.
getBatchCode
());
transactions
.
setUnitPrice
(
String
.
valueOf
(
outboundOrderItem
.
getUnitPrice
()));
transactions
.
setInventoryId
(
inventory
.
getId
());
// 库存表Id
transactions
.
setReferenceId
(
outboundOrderItem
.
getOutboundOrderId
());
//关联单号,相当于主记录-盘点主表
transactions
.
setReferenceItemId
(
outboundOrderItem
.
getId
());
// 盘点子表id
transactions
.
setMaterialId
(
outboundOrderItem
.
getMaterialId
());
transactions
.
setWarehouseId
(
outboundOrderItem
.
getWarehouseId
());
transactions
.
setLocationId
(
outboundOrderItem
.
getLocationId
());
OutboundOrders
outboundOrders
=
outboundOrderMapper
.
selectOutboundOrdersById
(
outboundOrderItem
.
get
Warehouse
Id
());
OutboundOrders
outboundOrders
=
outboundOrderMapper
.
selectOutboundOrdersById
(
outboundOrderItem
.
get
OutboundOrder
Id
());
transactions
.
setOwnerId
(
outboundOrders
.
getOwnerId
());
transactions
.
setQuantityBefore
(
Long
.
valueOf
(
quantity
));
// 变更前数量
transactions
.
setQuantityAfter
(
inventory
.
getQuantity
());
// 变更后数量
...
...
@@ -175,10 +177,7 @@ public class InventoryServiceImpl implements IInventoryService
transactions
.
setTransactionTime
(
nowDate
);
transactions
.
setOperatedBy
(
SystemUtils
.
getUserName
());
int
inventoryTransactions
=
insertInventoryTransactions
.
insertInventoryTransactions
(
transactions
);
if
(
inventoryTransactions
<
0
)
{
return
-
1
;
}
insertInventoryTransactions
.
insertInventoryTransactions
(
transactions
);
}
RefreshInventory
(
inventoryIds
);
}
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrderItemsServiceImpl.java
View file @
db0c0a3a
...
...
@@ -11,7 +11,7 @@ import com.ruoyi.common.utils.StringUtils;
import
com.ruoyi.common.utils.bean.BeanUtils
;
import
com.ruoyi.inventory.domain.InboundOrderItems
;
import
com.ruoyi.inventory.domain.InboundOrders
;
import
com.ruoyi.inventory.domain.vo.InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.
inboundVO.
InboundTemplateVO
;
import
com.ruoyi.inventory.domain.vo.OutboundOrdersSummaryVO
;
import
com.ruoyi.inventory.domain.vo.OutboundTemplateVO
;
import
org.springframework.beans.factory.annotation.Autowired
;
...
...
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/OutboundOrdersServiceImpl.java
View file @
db0c0a3a
...
...
@@ -4,6 +4,7 @@ import java.util.*;
import
java.util.stream.Collectors
;
import
com.ruoyi.common.annotation.SerialExecution
;
import
com.ruoyi.common.config.WarehouseConfig
;
import
com.ruoyi.common.core.domain.entity.Materials
;
import
com.ruoyi.common.exception.ServiceException
;
import
com.ruoyi.common.utils.DateUtils
;
...
...
@@ -28,6 +29,10 @@ import org.springframework.util.CollectionUtils;
/**
* 出库单主Service业务层处理
* 核心修正:
* 1. 库存匹配Key统一为 仓库ID_物料ID_库位ID_库存类型
* 2. 确保inventoryType完整参与匹配
* 3. 库存扣减后≤0时强制设置inventory_status=0
*
* @author ruoyi
* @date 2025-12-03
...
...
@@ -54,6 +59,10 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
private
MaterialsServiceImpl
materialsService
;
@Autowired
private
StorageLocationsServiceImpl
storageLocationsService
;
@Autowired
private
InventoryMapper
inventoryMapper
;
/**
* 查询出库单主
*
...
...
@@ -63,7 +72,6 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
@Override
public
OutboundOrders
selectOutboundOrdersById
(
String
id
)
{
return
outboundOrdersMapper
.
selectOutboundOrdersById
(
id
);
}
...
...
@@ -112,7 +120,6 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
outboundOrdersMapper
.
deleteOutboundOrderItemsByOrderId
(
outboundOrders
.
getId
());
outboundOrderLogMapper
.
deleteOutboundOrderLogByOrdersId
(
outboundOrders
.
getId
());
outboundOrders
.
setUpdateUserCode
(
SystemUtils
.
getUserName
());
outboundOrders
.
setUpdateTime
(
DateUtils
.
getNowDate
());
insertOutboundOrderItems
(
outboundOrders
);
...
...
@@ -147,42 +154,161 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
outboundOrdersMapper
.
deleteOutboundOrderItemsByOrderId
(
id
);
return
outboundOrdersMapper
.
deleteOutboundOrdersById
(
id
);
}
@SerialExecution
(
group
=
"inventoryRefresh"
,
fair
=
true
)
@Override
public
int
ship
(
OutboundOrders
outboundOrders
)
{
OutboundOrderItems
outboundOrderItems1
=
new
OutboundOrderItems
();
outboundOrderItems1
.
setOutboundOrderId
(
outboundOrders
.
getId
());
outboundOrderItems1
.
setDivisor
(
null
);
List
<
OutboundOrderItems
>
outboundOrderItems
=
outboundOrderItemsMapper
.
selectOutboundOrderItemsList
(
outboundOrderItems1
);
List
<
OutboundOrderItems
>
outboundOrderItems2
=
outboundOrderItems
;
// 1. 查询当前出库单的所有明细
OutboundOrderItems
query
=
new
OutboundOrderItems
();
query
.
setOutboundOrderId
(
outboundOrders
.
getId
());
query
.
setDivisor
(
null
);
List
<
OutboundOrderItems
>
outboundOrderItems
=
outboundOrderItemsMapper
.
selectOutboundOrderItemsList
(
query
);
// 2. 更新明细和订单状态
OutboundOrderLog
outboundOrderLog
=
new
OutboundOrderLog
();
String
updateUser
=
SystemUtils
.
getUserName
();
Date
updateTime
=
DateUtils
.
getNowDate
();
for
(
OutboundOrderItems
item
:
outboundOrderItems
)
{
item
.
setItemStatus
(
3L
);
item
.
setUpdateBy
(
updateUser
);
item
.
setUpdateTime
(
updateTime
);
outboundOrderItemsMapper
.
updateOutboundOrderItems
(
item
);
outboundOrderLog
.
setId
(
item
.
getId
());
outboundOrderLog
.
setItemStatus
(
item
.
getItemStatus
());
outboundOrderLogMapper
.
updateOutboundOrderLog
(
outboundOrderLog
);
}
for
(
OutboundOrderItems
outboundOrderItem
:
outboundOrderItems
)
{
outboundOrders
.
setOrderStatus
(
2L
);
outboundOrders
.
setUpdateTime
(
updateTime
);
outboundOrders
.
setUpdateUserCode
(
updateUser
);
outboundOrdersMapper
.
updateOutboundOrders
(
outboundOrders
);
outboundOrderItem
.
setItemStatus
(
3
l
);
outboundOrderItemsMapper
.
updateOutboundOrderItems
(
outboundOrderItem
);
// 3. 执行库存扣减(包含inventoryType匹配 + 0值状态更新)
this
.
deductInventory
(
outboundOrderItems
,
updateUser
,
updateTime
);
outboundOrderLog
.
setId
(
outboundOrderItem
.
getId
());
outboundOrderLog
.
setItemStatus
(
outboundOrderItem
.
getItemStatus
());
outboundOrderLogMapper
.
updateOutboundOrderLog
(
outboundOrderLog
);
return
1
;
}
/**
* 核心库存扣减逻辑
* 1. 按 仓库ID_物料ID_库位ID_库存类型 匹配库存
* 2. 扣减后数量≤0时设置inventory_status=0
* @param outboundOrderItems 出库明细
* @param updateUser 操作人
* @param updateTime 操作时间
*/
private
void
deductInventory
(
List
<
OutboundOrderItems
>
outboundOrderItems
,
String
updateUser
,
Date
updateTime
)
{
if
(
CollectionUtils
.
isEmpty
(
outboundOrderItems
))
{
return
;
}
// 1. 预加载库存映射:Key=仓库ID_物料ID_库位ID_库存类型 Value=库存对象
Map
<
String
,
Inventory
>
inventoryMap
=
this
.
loadInventoryMap
();
// 2. 构建扣减数量Map:Key=仓库ID_物料ID_库位ID_库存类型 Value=总扣减数量
Map
<
String
,
Long
>
deductQtyMap
=
this
.
buildDeductQtyMap
(
outboundOrderItems
);
// 3. 遍历扣减Map,执行扣减+状态更新
List
<
Inventory
>
needUpdateList
=
new
ArrayList
<>();
for
(
Map
.
Entry
<
String
,
Long
>
entry
:
deductQtyMap
.
entrySet
())
{
String
key
=
entry
.
getKey
();
Long
deductQty
=
entry
.
getValue
();
// 匹配库存
Inventory
inventory
=
inventoryMap
.
get
(
key
);
if
(
inventory
==
null
)
{
String
[]
keyParts
=
key
.
split
(
"_"
);
String
warehouseId
=
keyParts
.
length
>
0
?
keyParts
[
0
]
:
""
;
String
materialId
=
keyParts
.
length
>
1
?
keyParts
[
1
]
:
""
;
String
locationId
=
keyParts
.
length
>
2
?
keyParts
[
2
]
:
""
;
String
inventoryType
=
keyParts
.
length
>
3
?
keyParts
[
3
]
:
""
;
throw
new
ServiceException
(
String
.
format
(
"仓库[%s]物料[%s]库位[%s]库存类型[%s]的库存不存在,无法扣减"
,
warehouseId
,
materialId
,
locationId
,
inventoryType
));
}
outboundOrders
.
setId
(
outboundOrders
.
getId
());
outboundOrders
.
setOrderStatus
(
2
l
);
outboundOrders
.
setUpdateTime
(
DateUtils
.
getNowDate
());
outboundOrders
.
setUpdateUserCode
(
SystemUtils
.
getUserName
());
outboundOrdersMapper
.
updateOutboundOrders
(
outboundOrders
);
// 执行数量扣减
Long
currentQty
=
Optional
.
ofNullable
(
inventory
.
getQuantity
()).
orElse
(
0L
);
Long
newQty
=
currentQty
-
deductQty
;
inventory
.
setQuantity
(
newQty
);
inventoryService
.
ship
(
outboundOrderItems2
);
return
1
;
// 核心规则:扣减后数量≤0 → 状态置0
if
(
newQty
<=
0
)
{
inventory
.
setInventoryStatus
(
0L
);
}
// 补充审计字段
inventory
.
setUpdateBy
(
updateUser
);
inventory
.
setUpdateTime
(
updateTime
);
needUpdateList
.
add
(
inventory
);
}
// 4. 批量更新库存
if
(!
needUpdateList
.
isEmpty
())
{
inventoryMapper
.
batchUpdateInventory
(
needUpdateList
);
// 刷新库存缓存
List
<
String
>
inventoryIds
=
needUpdateList
.
stream
()
.
map
(
Inventory:
:
getId
)
.
distinct
()
.
collect
(
Collectors
.
toList
());
inventoryService
.
RefreshInventory
(
inventoryIds
);
}
}
/**
* 预加载库存Map
* Key规则:仓库ID_物料ID_库位ID_库存类型
*/
private
Map
<
String
,
Inventory
>
loadInventoryMap
()
{
Inventory
query
=
new
Inventory
();
query
.
setInventoryStatus
(
1L
);
query
.
setIsUsed
(
1L
);
List
<
Inventory
>
inventoryList
=
inventoryService
.
selectInventoryList
(
query
);
if
(
CollectionUtils
.
isEmpty
(
inventoryList
))
{
return
Collections
.
emptyMap
();
}
Map
<
String
,
Inventory
>
inventoryMap
=
new
HashMap
<>();
for
(
Inventory
inv
:
inventoryList
)
{
String
key
=
String
.
join
(
"_"
,
Optional
.
ofNullable
(
inv
.
getWarehousesId
()).
orElse
(
""
),
Optional
.
ofNullable
(
inv
.
getMaterialId
()).
orElse
(
""
),
Optional
.
ofNullable
(
inv
.
getLocationId
()).
orElse
(
""
),
Optional
.
ofNullable
(
inv
.
getInventoryType
()).
map
(
String:
:
valueOf
).
orElse
(
""
)
);
// 重复key保留第一个(避免覆盖)
if
(!
inventoryMap
.
containsKey
(
key
))
{
inventoryMap
.
put
(
key
,
inv
);
}
}
return
inventoryMap
;
}
/**
* 构建扣减数量Map
* Key规则:仓库ID_物料ID_库位ID_库存类型(和库存Map完全对齐)
*/
private
Map
<
String
,
Long
>
buildDeductQtyMap
(
List
<
OutboundOrderItems
>
items
)
{
Map
<
String
,
Long
>
deductQtyMap
=
new
HashMap
<>();
for
(
OutboundOrderItems
item
:
items
)
{
String
key
=
String
.
join
(
"_"
,
Optional
.
ofNullable
(
item
.
getWarehouseId
()).
orElse
(
""
),
Optional
.
ofNullable
(
item
.
getMaterialId
()).
orElse
(
""
),
Optional
.
ofNullable
(
item
.
getLocationId
()).
orElse
(
""
),
Optional
.
ofNullable
(
item
.
getInventoryType
()).
map
(
String:
:
valueOf
).
orElse
(
""
)
);
// 累加扣减数量
Long
qty
=
Optional
.
ofNullable
(
item
.
getActualQuantity
()).
orElse
(
0L
);
deductQtyMap
.
put
(
key
,
deductQtyMap
.
getOrDefault
(
key
,
0L
)
+
qty
);
}
return
deductQtyMap
;
}
@Override
public
List
<
Map
<
String
,
String
>>
outboundOrdersTopTenByQuantity
()
{
List
<
Map
<
String
,
String
>>
o
=
outboundOrdersMapper
.
SelectOutboundOrdersMaterialsTopTenByQuantity
();
return
o
;
return
outboundOrdersMapper
.
SelectOutboundOrdersMaterialsTopTenByQuantity
();
}
@Override
...
...
@@ -192,7 +318,6 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
@Override
public
String
outboundOrdersCount
()
{
return
outboundOrdersMapper
.
outboundOrdersCount
();
}
...
...
@@ -204,48 +329,41 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
public
void
insertOutboundOrderItems
(
OutboundOrders
outboundOrders
)
{
List
<
OutboundOrderItems
>
outboundOrderItemsList
=
outboundOrders
.
getOutboundOrderItemsList
();
String
id
=
outboundOrders
.
getId
();
// 1. 先做空列表校验(提前返回,避免无效逻辑)
if
(
outboundOrderItemsList
==
null
||
outboundOrderItemsList
.
isEmpty
())
{
if
(
CollectionUtils
.
isEmpty
(
outboundOrderItemsList
))
{
return
;
}
//
2. 库存校验:失败时抛异常(核心修正:! 取反 + 异常抛出后代码立即终止)
//
库存校验:失败时抛异常
boolean
isValid
=
inventoryService
.
inventoryLockValidation
(
outboundOrderItemsList
);
if
(!
isValid
)
{
// 校验失败(返回false)时抛异常
throw
new
RuntimeException
(
"库存被修改请重新确认"
);
// 抛异常后,方法立即停止运行
if
(!
isValid
)
{
throw
new
RuntimeException
(
"库存被修改请重新确认"
);
}
//
2.
为明细设置订单ID和主键ID
// 为明细设置订单ID和主键ID
for
(
OutboundOrderItems
items
:
outboundOrderItemsList
)
{
items
.
setOutboundOrderId
(
id
);
items
.
setOrderId
(
outboundOrders
.
getOrderId
());
// 生成无横线的UUID作为主键
items
.
setId
(
UUID
.
randomUUID
().
toString
().
replace
(
"-"
,
""
));
}
//
3.
批量插入出库单明细
// 批量插入出库单明细
outboundOrdersMapper
.
batchOutboundOrderItems
(
outboundOrderItemsList
);
//
4. 正确拷贝明细列表到日志列表(修复核心错误:遍历逐个拷贝)
//
拷贝明细到日志列表
List
<
String
>
inventoryIds
=
new
ArrayList
<>();
List
<
OutboundOrderLog
>
outboundOrderLogs
=
new
ArrayList
<>();
for
(
OutboundOrderItems
items
:
outboundOrderItemsList
)
{
OutboundOrderLog
log
=
new
OutboundOrderLog
();
BeanUtils
.
copyProperties
(
items
,
log
);
// 单个对象属性拷贝
BeanUtils
.
copyProperties
(
items
,
log
);
log
.
setOrderId
(
items
.
getOutboundOrderId
());
outboundOrderLogs
.
add
(
log
);
inventoryIds
.
add
(
log
.
getInventoryId
());
deleteOutboundOrdersById
(
items
.
getId
());
}
//
5. 非空校验后插入日志(避免空列表触发SQL语法错误)
//
插入日志 + 刷新库存
if
(!
outboundOrderLogs
.
isEmpty
())
{
outboundOrderLogMapper
.
batchOutboundOrderLog
(
outboundOrderLogs
);
}
// 7. 非空校验后刷新库存
if
(!
inventoryIds
.
isEmpty
())
{
inventoryService
.
RefreshInventory
(
inventoryIds
);
}
...
...
@@ -253,13 +371,13 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
@Transactional
(
rollbackFor
=
Exception
.
class
)
@Override
public
String
importOutboundOrders
(
List
<
OutboundTemplateVO
>
inboundOrdersList
,
Boolean
isUpdateSupport
,
String
operName
,
Integer
orderType
)
{
// 1. 基础空值校验
(完全保留你的代码)
public
String
importOutboundOrders
(
List
<
OutboundTemplateVO
>
inboundOrdersList
,
Boolean
isUpdateSupport
,
String
operName
,
Integer
orderType
)
{
// 1. 基础空值校验
if
(
CollectionUtils
.
isEmpty
(
inboundOrdersList
))
{
throw
new
ServiceException
(
"导入数据不能为空!"
);
}
// 2. 初始化变量
(完全保留你的代码)
// 2. 初始化变量
int
totalMainSuccess
=
0
;
int
totalMainFailure
=
0
;
int
totalItemSuccess
=
0
;
...
...
@@ -274,12 +392,19 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
Map
<
String
,
List
<
OutboundOrderItems
>>
validItemMap
=
new
HashMap
<>();
boolean
hasValidateError
=
false
;
// 3. 按入库单号分组(完全保留你的代码)
// 3. 预加载映射缓存
Map
<
String
,
String
>
sapToMaterialIdMap
=
loadSapToMaterialIdMap
();
Map
<
String
,
String
>
locationNameToIdMap
=
loadLocationNameToIdMap
();
Map
<
String
,
String
>
warehouseNameToIdMap
=
loadWarehouseNameToIdMap
();
Map
<
String
,
String
>
ownerNameToIdMap
=
loadOwnerNameToIdMap
();
Map
<
String
,
AbstractMap
.
SimpleEntry
<
String
,
Long
>>
inventoryTOIdMap
=
loadInventoryTOIdMap
();
// 4. 按入库单号分组
Map
<
String
,
List
<
OutboundTemplateVO
>>
orderGroupMap
=
inboundOrdersList
.
stream
()
.
filter
(
vo
->
StringUtils
.
isNotBlank
(
vo
.
getOrderId
()))
.
collect
(
Collectors
.
groupingBy
(
OutboundTemplateVO:
:
getOrderId
));
//
4. 第一步:仅验证所有数据(完全保留你的代码)
//
5. 数据验证
for
(
Map
.
Entry
<
String
,
List
<
OutboundTemplateVO
>>
entry
:
orderGroupMap
.
entrySet
())
{
String
orderId
=
entry
.
getKey
();
List
<
OutboundTemplateVO
>
voList
=
entry
.
getValue
();
...
...
@@ -288,12 +413,12 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
try
{
OutboundTemplateVO
firstVO
=
voList
.
get
(
0
);
// 检查出库单是否已存在
OutboundOrders
outboundOrdersQuery
=
new
OutboundOrders
();
outboundOrdersQuery
.
setOrderId
(
orderId
);
List
<
OutboundOrders
>
existMains
=
outboundOrdersMapper
.
selectOutboundOrdersList
(
outboundOrdersQuery
);
if
(
CollectionUtils
.
isEmpty
(
existMains
)
&&
existMains
.
size
()
>
1
)
{
if
(
existMains
!=
null
&&
existMains
.
size
()
>
1
)
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】存在多条重复主表数据"
,
orderId
));
}
...
...
@@ -305,45 +430,41 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
mainDO
=
existMain
;
BeanUtils
.
copyProperties
(
firstVO
,
mainDO
,
"id"
,
"createBy"
,
"createTime"
);
mainDO
.
setUpdateBy
(
operId
);
mainDO
.
setWarehouseId
(
WarehouseConfig
.
DEFAULT_WAREHOUSE_ID
);
mainDO
.
setUpdateTime
(
now
);
mainDO
.
setUpdateUserCode
(
operId
);
}
else
{
mainDO
=
new
OutboundOrders
();
com
.
ruoyi
.
common
.
utils
.
bean
.
BeanUtils
.
copyProperties
(
firstVO
,
mainDO
,
BeanUtils
.
copyProperties
(
firstVO
,
mainDO
,
"sapNo"
,
"materialName"
,
"plannedQuantity"
,
"actualQuantity"
,
"plannedPackages"
,
"materialUnit"
,
"materialRemark"
);
if
(
StringUtils
.
isNotBlank
(
firstVO
.
getOwnerName
()))
{
Owners
ownerQuery
=
new
Owners
();
ownerQuery
.
setOwnerName
(
firstVO
.
getOwnerName
()
);
List
<
Owners
>
owners
=
ownersService
.
selectOwnersList
(
ownerQuery
);
if
(
CollectionUtils
.
isEmpty
(
owners
))
{
// 货主校验
String
ownerName
=
firstVO
.
getOwnerName
();
String
ownerId
=
firstVO
.
getOwnerId
(
);
if
(
StringUtils
.
isNotBlank
(
ownerName
))
{
String
mappedOwnerId
=
ownerNameToIdMap
.
get
(
ownerName
.
trim
());
if
(
StringUtils
.
isBlank
(
mappedOwnerId
))
{
throw
new
ServiceException
(
String
.
format
(
"业主【%s】不存在,无法新增入库单【%s】"
,
firstVO
.
getOwnerName
()
,
orderId
));
ownerName
,
orderId
));
}
if
(
firstVO
.
getOwnerId
()
!=
null
)
{
boolean
isMatch
=
owners
.
stream
().
anyMatch
(
o
->
firstVO
.
getOwnerId
().
equals
(
o
.
getId
()));
if
(!
isMatch
)
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】的业主ID【%s】与业主名称【%s】不匹配"
,
orderId
,
firstVO
.
getOwnerId
(),
firstVO
.
getOwnerName
()));
}
mainDO
.
setOwnerId
(
firstVO
.
getOwnerId
());
}
else
{
mainDO
.
setOwnerId
(
owners
.
get
(
0
).
getId
());
if
(
ownerId
!=
null
&&
!
ownerId
.
equals
(
mappedOwnerId
))
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】的业主ID【%s】与业主名称【%s】不匹配"
,
orderId
,
ownerId
,
ownerName
));
}
}
else
if
(
firstVO
.
getOwnerId
()
!=
null
)
{
Owners
ownerById
=
ownersService
.
selectOwnersById
(
firstVO
.
getOwnerId
());
mainDO
.
setOwnerId
(
mappedOwnerId
);
}
else
if
(
ownerId
!=
null
)
{
Owners
ownerById
=
ownersService
.
selectOwnersById
(
ownerId
);
if
(
ownerById
==
null
)
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】的业主ID【%s】不存在"
,
orderId
,
firstVO
.
getOwnerId
()
));
orderId
,
ownerId
));
}
mainDO
.
setOwnerId
(
firstVO
.
getOwnerId
()
);
mainDO
.
setOwnerId
(
ownerId
);
}
else
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】的业主名称/ID不能为空"
,
orderId
));
}
// 填充主表必填字段
mainDO
.
setId
(
UUID
.
randomUUID
().
toString
());
mainDO
.
setOrderId
(
orderId
);
mainDO
.
setOrderStatus
(
2L
);
...
...
@@ -357,14 +478,16 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
mainDO
.
setSortNo
(
Optional
.
ofNullable
(
mainDO
.
getSortNo
()).
orElse
(
0L
));
}
// 明细校验
for
(
int
i
=
0
;
i
<
voList
.
size
();
i
++)
{
OutboundTemplateVO
vo
=
voList
.
get
(
i
);
int
lineNo
=
i
+
1
;
OutboundOrderItems
itemDO
=
new
OutboundOrderItems
();
com
.
ruoyi
.
common
.
utils
.
bean
.
BeanUtils
.
copyProperties
(
vo
,
itemDO
,
BeanUtils
.
copyProperties
(
vo
,
itemDO
,
"orderId"
,
"systemNo"
,
"orderTypeId"
,
"batchId"
);
// 填充明细必填字段
itemDO
.
setId
(
UUID
.
randomUUID
().
toString
());
itemDO
.
setOrderId
(
orderId
);
itemDO
.
setBatchCode
(
Optional
.
ofNullable
(
mainDO
.
getBatchCode
()).
orElse
(
""
));
...
...
@@ -374,54 +497,53 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
itemDO
.
setCreateUserCode
(
operId
);
itemDO
.
setSortNo
(
0L
);
if
(
StringUtils
.
isBlank
(
vo
.
getSapNo
()))
{
// 物料SAP校验
String
sapNo
=
vo
.
getSapNo
()
!=
null
?
vo
.
getSapNo
().
trim
()
:
""
;
if
(
StringUtils
.
isBlank
(
sapNo
))
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】第%d条明细的物料SAP号不能为空"
,
orderId
,
lineNo
));
}
Materials
materialsQuery
=
new
Materials
();
materialsQuery
.
setSapNo
(
vo
.
getSapNo
());
List
<
Materials
>
materialsList
=
materialsService
.
selectMaterialsList
(
materialsQuery
);
if
(
CollectionUtils
.
isEmpty
(
materialsList
))
{
String
materialId
=
sapToMaterialIdMap
.
get
(
sapNo
);
if
(
StringUtils
.
isBlank
(
materialId
))
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】第%d条明细的SAP号【%s】对应的物料不存在"
,
orderId
,
lineNo
,
vo
.
getSapNo
()
));
orderId
,
lineNo
,
sapNo
));
}
itemDO
.
setMaterialId
(
material
sList
.
get
(
0
).
getId
()
);
itemDO
.
setMaterialId
(
material
Id
);
if
(
StringUtils
.
isBlank
(
vo
.
getLocationName
()))
{
// 库位校验
String
locationName
=
vo
.
getLocationName
()
!=
null
?
vo
.
getLocationName
().
trim
()
:
""
;
if
(
StringUtils
.
isBlank
(
locationName
))
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】第%d条明细的库位名称不能为空"
,
orderId
,
lineNo
));
}
StorageLocations
storageQuery
=
new
StorageLocations
();
storageQuery
.
setLocationCode
(
vo
.
getLocationName
());
List
<
StorageLocations
>
storageList
=
storageLocationsService
.
selectStorageLocationsList
(
storageQuery
);
if
(
CollectionUtils
.
isEmpty
(
storageList
))
{
String
locationId
=
locationNameToIdMap
.
get
(
locationName
);
if
(
StringUtils
.
isBlank
(
locationId
))
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】第%d条明细的库位【%s】不存在"
,
orderId
,
lineNo
,
vo
.
getLocationName
()
));
orderId
,
lineNo
,
locationName
));
}
itemDO
.
setLocationId
(
storageList
.
get
(
0
).
getId
()
);
Warehouses
warehouses
=
new
Warehouses
();
warehouses
.
setWarehousesName
(
vo
.
getWarehouseName
())
;
List
<
Warehouses
>
warehousesList
=
warehousesService
.
selectWarehousesList
(
warehouses
);
if
(
CollectionUtils
.
isEmpty
(
warehousesList
))
{
throw
new
ServiceException
(
String
.
format
(
"系统未配置仓库,无法导入入库单号【%s】的第%d条明细"
,
orderId
,
lineNo
));
itemDO
.
setLocationId
(
locationId
);
// 仓库校验
String
warehouseName
=
vo
.
getWarehouseName
()
!=
null
?
vo
.
getWarehouseName
().
trim
()
:
""
;
String
warehouseId
=
warehouseNameToIdMap
.
get
(
warehouseName
);
if
(
StringUtils
.
isBlank
(
warehouseId
))
{
throw
new
ServiceException
(
String
.
format
(
"系统未配置仓库
【%s】
,无法导入入库单号【%s】的第%d条明细"
,
warehouseName
,
orderId
,
lineNo
));
}
itemDO
.
setWarehouseId
(
warehousesList
.
get
(
0
).
getId
());
Inventory
itemsList
=
new
Inventory
();
itemsList
.
setWarehousesId
(
itemDO
.
getWarehouseId
());
itemsList
.
setMaterialId
(
itemDO
.
getMaterialId
());
itemsList
.
setLocationId
(
itemDO
.
getLocationId
());
List
<
Inventory
>
inventory
=
inventoryService
.
selectInventoryList
(
itemsList
);
if
(
CollectionUtils
.
isEmpty
(
inventory
))
{
itemDO
.
setWarehouseId
(
warehouseId
);
// 库存校验(包含inventoryType)
String
inventoryTypeStr
=
Optional
.
ofNullable
(
orderType
).
map
(
String:
:
valueOf
).
orElse
(
""
);
String
inventoryMatchKey
=
String
.
join
(
"_"
,
warehouseId
,
materialId
,
locationId
,
inventoryTypeStr
);
AbstractMap
.
SimpleEntry
<
String
,
Long
>
inventoryEntry
=
inventoryTOIdMap
.
get
(
inventoryMatchKey
);
if
(
inventoryEntry
==
null
)
{
throw
new
ServiceException
(
String
.
format
(
"入库单号【%s】第%d条明细:仓库【%s】+物料【%s】+库位【%s】组合的库存记录不存在"
,
orderId
,
lineNo
,
itemDO
.
getWarehouseName
(),
firstVO
.
getMaterialName
(),
firstVO
.
getLocationName
()
));
"入库单号【%s】第%d条明细:仓库【%s】+物料【%s】+库位【%s】
+库存类型【%s】
组合的库存记录不存在"
,
orderId
,
lineNo
,
vo
.
getWarehouseName
(),
vo
.
getMaterialName
(),
vo
.
getLocationName
(),
inventoryTypeStr
));
}
itemDO
.
setInventoryId
(
inventory
.
get
(
0
).
getId
());
itemDO
.
setItemStatus
(
3
l
);
itemDO
.
setInventoryId
(
inventory
Entry
.
getKey
());
itemDO
.
setInventoryType
(
inventoryTypeStr
);
// 填充库存类型
itemDO
.
setItemStatus
(
3
L
);
itemDOList
.
add
(
itemDO
);
}
...
...
@@ -436,26 +558,21 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
}
}
//
5. 有验证失败直接抛异常(完全保留你的代码)
//
6. 有验证失败直接抛异常
if
(
hasValidateError
)
{
throw
new
ServiceException
(
String
.
format
(
"验证失败,导入终止!失败详情:%s"
,
failureMsg
.
toString
()));
}
//
6. 验证全通过:统一执行入库/更新操作(完全保留你的代码)
//
7. 执行入库/更新操作
for
(
Map
.
Entry
<
String
,
OutboundOrders
>
entry
:
validMainMap
.
entrySet
())
{
String
orderId
=
entry
.
getKey
();
OutboundOrders
mainDO
=
entry
.
getValue
();
List
<
OutboundOrderItems
>
itemDOList
=
validItemMap
.
get
(
orderId
);
if
(
mainDO
!=
null
)
{
outboundOrdersMapper
.
insertOutboundOrders
(
mainDO
);
totalMainSuccess
++;
successMsg
.
append
(
String
.
format
(
"入库单号【%s】已新增;\n"
,
orderId
));
}
else
{
outboundOrdersMapper
.
updateOutboundOrders
(
mainDO
);
totalMainSuccess
++;
successMsg
.
append
(
String
.
format
(
"入库单号【%s】已更新;\n"
,
orderId
));
}
if
(!
CollectionUtils
.
isEmpty
(
itemDOList
))
{
int
itemSuccess
=
outboundOrderItemsMapper
.
batchInsertOutboundOrderItems
(
itemDOList
);
...
...
@@ -470,10 +587,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
}
}
//
========== 仅新增这一段代码(核心:事务提交后执行自定义逻辑) ==========
//
8. 事务提交后执行库存扣减
if
(
TransactionSynchronizationManager
.
isSynchronizationActive
())
{
// 保存当前需要的变量,用于事务提交后执行
Map
<
String
,
OutboundOrders
>
finalValidMainMap
=
new
HashMap
<>(
validMainMap
);
Map
<
String
,
List
<
OutboundOrderItems
>>
finalValidItemMap
=
new
HashMap
<>(
validItemMap
);
String
finalOperId
=
operId
;
Date
finalNow
=
now
;
...
...
@@ -481,17 +596,18 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
TransactionSynchronizationManager
.
registerSynchronization
(
new
TransactionSynchronization
()
{
@Override
public
void
afterCommit
()
{
// 事务提交后,调用你原来的executeCustomLogic方法
executeCustomLogic
(
finalValidMainMap
,
finalValidItemMap
,
finalOperId
,
finalNow
);
for
(
List
<
OutboundOrderItems
>
itemList
:
finalValidItemMap
.
values
())
{
deductInventory
(
itemList
,
finalOperId
,
finalNow
);
}
}
});
}
else
{
// 无事务时,直接执行(和你原有逻辑一致)
executeCustomLogic
(
validMainMap
,
validItemMap
,
operId
,
now
);
for
(
List
<
OutboundOrderItems
>
itemList
:
validItemMap
.
values
())
{
deductInventory
(
itemList
,
operId
,
now
);
}
}
// ========== 新增代码结束 ==========
//
8. 结果汇总(完全保留你的代码)
//
9. 结果汇总
if
(
totalMainFailure
>
0
||
totalItemFailure
>
0
)
{
String
finalFailureMsg
=
String
.
format
(
"导入结果:成功新增/更新%d个入库单,失败%d个;成功导入%d条明细,失败%d条。失败详情:%s"
,
...
...
@@ -507,59 +623,111 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
}
}
// 仅修改这个方法中【设置日志ID】的一行代码,其余完全保留
private
void
executeCustomLogic
(
Map
<
String
,
OutboundOrders
>
validMainMap
,
Map
<
String
,
List
<
OutboundOrderItems
>>
validItemMap
,
String
operId
,
Date
now
)
{
for
(
String
orderId
:
validMainMap
.
keySet
())
{
OutboundOrders
mainDO
=
validMainMap
.
get
(
orderId
);
List
<
OutboundOrderItems
>
itemList
=
validItemMap
.
get
(
orderId
);
System
.
out
.
println
(
String
.
format
(
"订单【%s】导入成功,主表ID:%s,明细数:%d"
,
orderId
,
mainDO
.
getId
(),
itemList
.
size
()));
List
<
OutboundOrderLog
>
outboundOrderLogs
=
new
ArrayList
<>();
for
(
OutboundOrderItems
item
:
itemList
)
{
OutboundOrderLog
outboundOrderLog
=
new
OutboundOrderLog
();
// ========== 唯一改动:设置日志ID = 明细ID ==========
outboundOrderLog
.
setId
(
item
.
getId
());
outboundOrderLog
.
setOrderId
(
item
.
getOutboundOrderId
());
BeanUtils
.
copyProperties
(
item
,
outboundOrderLog
);
outboundOrderLogs
.
add
(
outboundOrderLog
);
}
outboundOrderLogMapper
.
batchOutboundOrderLog
(
outboundOrderLogs
);
ship
(
itemList
);
// ========== 预加载映射辅助方法 ==========
private
Map
<
String
,
String
>
loadSapToMaterialIdMap
()
{
List
<
Materials
>
materialsList
=
materialsService
.
selectMaterialsList
(
new
Materials
());
if
(
CollectionUtils
.
isEmpty
(
materialsList
))
{
return
Collections
.
emptyMap
();
}
return
materialsList
.
stream
()
.
filter
(
m
->
StringUtils
.
isNotBlank
(
m
.
getSapNo
()))
.
collect
(
Collectors
.
toMap
(
m
->
m
.
getSapNo
().
trim
(),
Materials:
:
getId
,
(
k1
,
k2
)
->
k1
));
}
public
int
ship
(
List
<
OutboundOrderItems
>
outboundOrderItems
)
{
if
(!
outboundOrderItems
.
isEmpty
())
{
List
<
String
>
inventoryIds
=
new
ArrayList
<>();
// 手动收集inventoryId
for
(
OutboundOrderItems
outboundOrderItem
:
outboundOrderItems
)
{
// 直接用明细的inventoryId,不查日志!
String
inventoryId
=
outboundOrderItem
.
getInventoryId
();
if
(
StringUtils
.
isBlank
(
inventoryId
))
{
throw
new
ServiceException
(
"明细ID【"
+
outboundOrderItem
.
getId
()
+
"】的库存ID为空,无法扣减"
);
}
Inventory
inventory
=
inventoryService
.
selectInventoryById
(
inventoryId
);
if
(
inventory
==
null
)
{
throw
new
ServiceException
(
"库存ID【"
+
inventoryId
+
"】不存在,无法扣减"
);
}
private
Map
<
String
,
String
>
loadLocationNameToIdMap
()
{
StorageLocations
query
=
new
StorageLocations
();
query
.
setIsUsed
(
1L
);
List
<
StorageLocations
>
locationList
=
storageLocationsService
.
selectStorageLocationsList
(
query
);
if
(
CollectionUtils
.
isEmpty
(
locationList
))
{
return
Collections
.
emptyMap
();
}
return
locationList
.
stream
()
.
filter
(
l
->
StringUtils
.
isNotBlank
(
l
.
getLocationCode
()))
.
collect
(
Collectors
.
toMap
(
l
->
l
.
getLocationCode
().
trim
(),
StorageLocations:
:
getId
,
(
k1
,
k2
)
->
k1
));
}
// 扣减库存
inventory
.
setQuantity
(
inventory
.
getQuantity
()
-
outboundOrderItem
.
getActualQuantity
());
if
(
inventory
.
getQuantity
()
==
0
)
{
inventory
.
setInventoryStatus
(
0L
);
}
inventoryService
.
updateInventory
(
inventory
);
private
Map
<
String
,
String
>
loadWarehouseNameToIdMap
()
{
Warehouses
query
=
new
Warehouses
();
query
.
setIsUsed
(
1L
);
List
<
Warehouses
>
warehouseList
=
warehousesService
.
selectWarehousesList
(
query
);
if
(
CollectionUtils
.
isEmpty
(
warehouseList
))
{
return
Collections
.
emptyMap
();
}
return
warehouseList
.
stream
()
.
filter
(
w
->
StringUtils
.
isNotBlank
(
w
.
getWarehousesName
()))
.
collect
(
Collectors
.
toMap
(
w
->
w
.
getWarehousesName
().
trim
(),
Warehouses:
:
getId
,
(
k1
,
k2
)
->
k1
));
}
inventoryIds
.
add
(
inventoryId
);
// 收集库存ID用于刷新
}
inventoryService
.
RefreshInventory
(
inventoryIds
);
private
Map
<
String
,
String
>
loadOwnerNameToIdMap
()
{
List
<
Owners
>
ownerList
=
ownersService
.
selectOwnersList
(
new
Owners
());
if
(
CollectionUtils
.
isEmpty
(
ownerList
))
{
return
Collections
.
emptyMap
();
}
return
1
;
return
ownerList
.
stream
()
.
filter
(
o
->
StringUtils
.
isNotBlank
(
o
.
getOwnerName
()))
.
collect
(
Collectors
.
toMap
(
o
->
o
.
getOwnerName
().
trim
(),
Owners:
:
getId
,
(
k1
,
k2
)
->
k1
));
}
}
private
Map
<
String
,
AbstractMap
.
SimpleEntry
<
String
,
Long
>>
loadInventoryTOIdMap
()
{
Inventory
inventory
=
new
Inventory
();
inventory
.
setInventoryStatus
(
1L
);
inventory
.
setIsUsed
(
1L
);
List
<
Inventory
>
inventoryList
=
inventoryService
.
selectInventoryList
(
inventory
);
if
(
CollectionUtils
.
isEmpty
(
inventoryList
))
{
return
Collections
.
emptyMap
();
}
Map
<
String
,
AbstractMap
.
SimpleEntry
<
String
,
Long
>>
emptyLocationMap
=
inventoryList
.
stream
()
.
filter
(
inv
->
StringUtils
.
isNotBlank
(
inv
.
getWarehousesId
())
&&
StringUtils
.
isNotBlank
(
inv
.
getMaterialId
())
&&
inv
.
getInventoryType
()
!=
null
&&
StringUtils
.
isNotBlank
(
inv
.
getId
())
&&
StringUtils
.
isBlank
(
inv
.
getLocationId
()))
.
collect
(
Collectors
.
toMap
(
inv
->
String
.
join
(
"_"
,
inv
.
getWarehousesId
().
trim
(),
inv
.
getMaterialId
().
trim
(),
""
,
inv
.
getInventoryType
().
toString
()),
inv
->
new
AbstractMap
.
SimpleEntry
<>(
inv
.
getId
().
trim
(),
Optional
.
ofNullable
(
inv
.
getQuantity
()).
orElse
(
0L
)),
(
k1
,
k2
)
->
k1
,
HashMap:
:
new
));
Map
<
String
,
AbstractMap
.
SimpleEntry
<
String
,
Long
>>
nonEmptyLocationMap
=
inventoryList
.
stream
()
.
filter
(
inv
->
StringUtils
.
isNotBlank
(
inv
.
getWarehousesId
())
&&
StringUtils
.
isNotBlank
(
inv
.
getMaterialId
())
&&
StringUtils
.
isNotBlank
(
inv
.
getLocationId
())
&&
StringUtils
.
isNotBlank
(
inv
.
getId
())
&&
inv
.
getInventoryType
()
!=
null
)
.
collect
(
Collectors
.
toMap
(
inv
->
String
.
join
(
"_"
,
inv
.
getWarehousesId
().
trim
(),
inv
.
getMaterialId
().
trim
(),
inv
.
getLocationId
().
trim
(),
inv
.
getInventoryType
().
toString
()),
inv
->
new
AbstractMap
.
SimpleEntry
<>(
inv
.
getId
().
trim
(),
Optional
.
ofNullable
(
inv
.
getQuantity
()).
orElse
(
0L
)),
(
k1
,
k2
)
->
k1
,
HashMap:
:
new
));
emptyLocationMap
.
putAll
(
nonEmptyLocationMap
);
return
emptyLocationMap
;
}
}
\ No newline at end of file
ruoyi-inventory/src/main/java/com/ruoyi/inventory/service/impl/StorageLocationsServiceImpl.java
View file @
db0c0a3a
...
...
@@ -5,6 +5,7 @@ import java.util.Date;
import
java.util.List
;
import
java.util.Map
;
import
com.ruoyi.common.config.WarehouseConfig
;
import
com.ruoyi.common.core.domain.entity.Materials
;
import
com.ruoyi.common.exception.ServiceException
;
import
com.ruoyi.common.utils.DateUtils
;
...
...
@@ -50,16 +51,20 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
public
StorageLocations
selectStorageLocationsById
(
String
id
)
{
StorageLocations
storageLocations
=
storageLocationsMapper
.
selectStorageLocationsById
(
id
);
String
[]
AllowedCategoryIds
=
storageLocations
.
getAllowedCategoryIds
().
split
(
","
);
String
AllowedCategoryName
=
""
;
for
(
String
AllowedCategoryId
:
AllowedCategoryIds
)
{
Materials
materials
=
materialsMapper
.
selectMaterialsById
(
AllowedCategoryId
);
if
(
materials
!=
null
&&
materials
.
getMaterialName
()
!=
null
)
{
String
categoryName
=
materials
.
getMaterialName
().
trim
();
// 去除首尾空格
if
(
AllowedCategoryName
!=
""
)
{
AllowedCategoryName
+=
","
;
if
(
storageLocations
.
getAllowedCategoryIds
()
!=
null
)
{
String
[]
AllowedCategoryIds
=
storageLocations
.
getAllowedCategoryIds
().
split
(
","
);
if
(
AllowedCategoryIds
!=
null
&&
AllowedCategoryIds
.
length
>
0
)
{
for
(
String
AllowedCategoryId
:
AllowedCategoryIds
)
{
Materials
materials
=
materialsMapper
.
selectMaterialsById
(
AllowedCategoryId
);
if
(
materials
!=
null
&&
materials
.
getMaterialName
()
!=
null
)
{
String
categoryName
=
materials
.
getMaterialName
().
trim
();
// 去除首尾空格
if
(
AllowedCategoryName
!=
""
)
{
AllowedCategoryName
+=
","
;
}
AllowedCategoryName
+=
categoryName
;
}
}
AllowedCategoryName
+=
categoryName
;
}
}
storageLocations
.
setAllowedCategoryNames
(
AllowedCategoryName
);
...
...
@@ -260,6 +265,7 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
StorageLocations
storageLocations
=
new
StorageLocations
();
// 拷贝基础属性
BeanUtils
.
copyProperties
(
templateVO
,
storageLocations
);
storageLocations
.
setLocationName
(
templateVO
.
getLocationCode
());
// 字段类型转换与赋值
storageLocations
.
setId
(
UUID
.
randomUUID
().
toString
());
...
...
@@ -274,7 +280,8 @@ public class StorageLocationsServiceImpl implements IStorageLocationsService
storageLocations
.
setCreateBy
(
operId
);
storageLocations
.
setCreateTime
(
now
);
storageLocations
.
setCreateUserCode
(
operId
);
storageLocations
.
setWarehousesId
(
"572ba484-199c-45d9-9735-610928ed5c70"
);
storageLocations
.
setWarehousesCode
(
"固定仓库"
);
storageLocations
.
setWarehousesId
(
WarehouseConfig
.
DEFAULT_WAREHOUSE_ID
);
// 设置默认值
if
(
storageLocations
.
getIsUsed
()
==
null
)
{
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/InboundOrdersMapper.xml
View file @
db0c0a3a
...
...
@@ -231,8 +231,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</foreach>
</insert>
<!-- 统计入库次数-->
<select
id=
"countInboundOrders"
resultType=
"int"
parameterType=
"String"
>
select count(id)
...
...
@@ -247,27 +245,36 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result
column=
"total_money"
property=
"totalMoney"
jdbcType=
"DECIMAL"
/>
</resultMap>
<select
id=
"countInboundMaterialQuantity"
resultMap=
"InboundMaterialTotalResultMap"
parameterType=
"String"
>
select m.material_name,
COALESCE(SUM(ioi.actual_quantity), 0) as total_quantity
from materials as m
left join inbound_order_items as ioi
on m.id = ioi.material_id
left join inbound_orders as io
on io.id = ioi.inbound_order_id
and io.order_status = 2
group by m.id, m.material_name
order by total_quantity desc
SELECT t.material_name, t.total_quantity
FROM (
SELECT m.material_name,
COALESCE(SUM(ioi.actual_quantity), 0) as total_quantity
FROM materials as m
LEFT JOIN inbound_order_items as ioi ON m.id = ioi.material_id
LEFT JOIN inbound_orders as io ON io.id = ioi.inbound_order_id AND io.order_status = 2
WHERE m.is_used = 1 AND m.is_active = 1
GROUP BY m.id, m.material_name
ORDER BY total_quantity DESC
LIMIT 10
) t
ORDER BY t.total_quantity ASC;
</select>
<select
id=
"countInboundMaterialMoney"
resultMap=
"InboundMaterialTotalResultMap"
parameterType=
"String"
>
select m.material_name,
COALESCE(sum(ioi.actual_quantity * ioi.unit_price), 0) as total_money
from materials as m
left join inbound_order_items as ioi
on m.id = ioi.material_id
left join inbound_orders as io
on io.id = ioi.inbound_order_id
and io.order_status = 2
group by m.id, m.material_name
order by total_money desc
select t.material_name,t.total_money
from(
select m.material_name,
COALESCE(sum(ioi.actual_quantity * ioi.unit_price), 0) as total_money
from materials as m
left join inbound_order_items as ioi
on m.id = ioi.material_id
left join inbound_orders as io
on io.id = ioi.inbound_order_id
and io.order_status = 2
where m.is_used = 1 and m.is_active = 1
group by m.id
order by total_money desc
limit 10
) t
order by total_money asc
</select>
</mapper>
\ No newline at end of file
ruoyi-inventory/src/main/resources/mapper/inventory/InventoryMapper.xml
View file @
db0c0a3a
...
...
@@ -10,6 +10,7 @@
<result
property=
"orderId"
column=
"order_id"
/>
<result
property=
"materialId"
column=
"material_id"
/>
<result
property=
"materialName"
column=
"material_name"
/>
<result
property=
"hazardId"
column=
"hazard_id"
/>
<result
property=
"batchId"
column=
"batch_id"
/>
<result
property=
"warehousesCode"
column=
"warehouses_code"
/>
<result
property=
"warehousesName"
column=
"warehouses_name"
/>
...
...
@@ -401,6 +402,7 @@
i.order_id,
i.material_id,
m.material_name,
m.hazard_id,
i.batch_id,
i.location_id,
sl.location_name,
...
...
@@ -563,6 +565,9 @@ and inventory_status = '1'
and i.unit_price > 0
and i.last_inbound_time >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
and i.last_inbound_time
<
DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
where
m.is_used =1
and m.is_active =1
group by m.id, m.material_name
order by value desc, m.material_name asc
</select>
...
...
@@ -577,6 +582,9 @@ and inventory_status = '1'
and i.is_used = 1
and i.last_inbound_time >= DATE_FORMAT(CURDATE(), '%Y-%m-01')
and i.last_inbound_time
<
DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
where
m.is_used =1
and m.is_active =1
group by m.id, m.material_name
order by value desc, m.material_name asc
</select>
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/InventoryTransactionsMapper.xml
View file @
db0c0a3a
...
...
@@ -87,7 +87,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"createUserCode != null"
>
create_user_code,
</if>
<if
test=
"updateTime != null"
>
update_time,
</if>
<if
test=
"updateUserCode != null"
>
update_user_code,
</if>
</trim>
<if
test=
"unitPrice != null"
>
unit_price,
</if>
</trim>
<trim
prefix=
"values ("
suffix=
")"
suffixOverrides=
","
>
<if
test=
"id != null"
>
#{id},
</if>
<if
test=
"transactionType != null"
>
#{transactionType},
</if>
...
...
@@ -111,6 +112,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"createUserCode != null"
>
#{createUserCode},
</if>
<if
test=
"updateTime != null"
>
#{updateTime},
</if>
<if
test=
"updateUserCode != null"
>
#{updateUserCode},
</if>
<if
test=
"unitPrice != null"
>
#{unitPrice},
</if>
</trim>
</insert>
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/MaterialsMapper.xml
View file @
db0c0a3a
...
...
@@ -8,6 +8,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result
property=
"id"
column=
"id"
/>
<result
property=
"materialCode"
column=
"material_code"
/>
<result
property=
"materialName"
column=
"material_name"
/>
<result
property=
"materialEname"
column=
"material_ename"
/>
<result
property=
"sapNo"
column=
"sap_no"
/>
<result
property=
"tsCode"
column=
"ts_code"
/>
<result
property=
"categoryCode"
column=
"category_code"
/>
...
...
@@ -36,7 +37,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql
id=
"selectMaterialsVo"
>
select id, material_code, material_name, sap_no, ts_code, category_code, hazard_id, specification, material_unit, unit_weight, package_weight, total_weight, volume, shelf_life_days, storage_temperature, special_requirements, is_batch_managed, is_serial_managed, min_stock_level, max_stock_level, is_used, is_active, risk_level, sort_no, create_time, create_user_code, update_time, update_user_code from materials
select id, material_code, material_name,
material_ename,
sap_no, ts_code, category_code, hazard_id, specification, material_unit, unit_weight, package_weight, total_weight, volume, shelf_life_days, storage_temperature, special_requirements, is_batch_managed, is_serial_managed, min_stock_level, max_stock_level, is_used, is_active, risk_level, sort_no, create_time, create_user_code, update_time, update_user_code from materials
</sql>
<select
id=
"selectMaterialsList"
parameterType=
"Materials"
resultMap=
"MaterialsResult"
>
...
...
@@ -101,6 +102,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"id != null"
>
id,
</if>
<if
test=
"materialCode != null"
>
material_code,
</if>
<if
test=
"materialName != null"
>
material_name,
</if>
<if
test=
"materialEname != null"
>
material_ename,
</if>
<if
test=
"sapNo != null"
>
sap_no,
</if>
<if
test=
"tsCode != null"
>
ts_code,
</if>
<if
test=
"categoryCode != null"
>
category_code,
</if>
...
...
@@ -131,6 +133,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if
test=
"id != null"
>
#{id},
</if>
<if
test=
"materialCode != null"
>
#{materialCode},
</if>
<if
test=
"materialName != null"
>
#{materialName},
</if>
<if
test=
"materialEname != null"
>
#{materialEname},
</if>
<if
test=
"sapNo != null"
>
#{sapNo},
</if>
<if
test=
"tsCode != null"
>
#{tsCode},
</if>
<if
test=
"categoryCode != null"
>
#{categoryCode},
</if>
...
...
@@ -164,6 +167,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<trim
prefix=
"SET"
suffixOverrides=
","
>
<if
test=
"materialCode != null"
>
material_code = #{materialCode},
</if>
<if
test=
"materialName != null"
>
material_name = #{materialName},
</if>
<if
test=
"materialEname != null"
>
material_ename = #{materialEname},
</if>
<if
test=
"sapNo != null"
>
sap_no = #{sapNo},
</if>
<if
test=
"tsCode != null"
>
ts_code = #{tsCode},
</if>
<if
test=
"categoryCode != null"
>
category_code = #{categoryCode},
</if>
...
...
ruoyi-inventory/src/main/resources/mapper/inventory/OutboundOrdersMapper.xml
View file @
db0c0a3a
...
...
@@ -315,6 +315,9 @@
and ooi.is_used = 1
and ooi.shipped_at >= DATE_FORMAT(CURDATE(), '%Y-%m-01 00:00:00')
and ooi.shipped_at
<
DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01 00:00:00')
where
m.is_used =1
and m.is_active =1
group by m.id, m.material_name
order by value desc
limit 10;
...
...
@@ -330,6 +333,9 @@
and ooi.is_used = 1
and ooi.shipped_at >= DATE_FORMAT(CURDATE(), '%Y-%m-01 00:00:00')
and ooi.shipped_at
<
DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01 00:00:00')
where
m.is_used =1
and m.is_active =1
group by m.id, m.material_name
order by value desc
limit 10;
...
...
@@ -338,4 +344,15 @@
select count(*) from outbound_orders where is_used = 1 and order_status=2 and inbound_date
>
= DATE_FORMAT(CURDATE(), '%Y-%m-01')
and inbound_date
<
DATE_FORMAT(DATE_ADD(CURDATE(), INTERVAL 1 MONTH), '%Y-%m-01')
</select>
<update
id=
"batchUpdateInventory"
>
<foreach
collection=
"list"
item=
"item"
separator=
";"
>
UPDATE inventory
SET quantity = #{item.quantity},
inventory_status = #{item.inventoryStatus},
update_by = #{item.updateBy},
update_time = #{item.updateTime}
WHERE id = #{item.id}
</foreach>
</update>
</mapper>
\ No newline at end of file
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论