Commit 15102e6e by yubin

出库

parent 389f53a1
...@@ -68,3 +68,12 @@ export function listInventoryByMaterialId(materialId) { ...@@ -68,3 +68,12 @@ export function listInventoryByMaterialId(materialId) {
params: { materialId: materialId } params: { materialId: materialId }
}) })
} }
export function Ship(data) {
return request({
url: '/inventory/inventory/ship',
method: 'post',
data: data
})
}
...@@ -51,3 +51,11 @@ export function listWarehouseInventory(warehouseId) { ...@@ -51,3 +51,11 @@ export function listWarehouseInventory(warehouseId) {
params: { warehouseId: warehouseId } params: { warehouseId: warehouseId }
}) })
} }
export function ship(data) {
return request({
url: '/inventory/orders/ship',
method: 'post',
data: data
})
}
\ No newline at end of file
...@@ -66,7 +66,7 @@ ...@@ -66,7 +66,7 @@
</el-col> </el-col>
</el-row> </el-row>
<!-- 库存信息列表 --> <!-- 库存信息列表 - 添加库存ID列 -->
<el-row v-if="form.materialId && form.materialId.trim()" style="margin: 10px 0;"> <el-row v-if="form.materialId && form.materialId.trim()" style="margin: 10px 0;">
<el-col :span="24"> <el-col :span="24">
<div style="margin-bottom: 8px; font-weight: 600; color: #1989fa;"> <div style="margin-bottom: 8px; font-weight: 600; color: #1989fa;">
...@@ -81,11 +81,10 @@ ...@@ -81,11 +81,10 @@
highlight-current-row highlight-current-row
stripe stripe
empty-text="暂无库存数据" empty-text="暂无库存数据"
@selection-change="handleSelectionChange"
@row-click="handleRowClick" @row-click="handleRowClick"
:row-key="item => item.id"
> >
<el-table-column type="selection" width="55" /> <el-table-column prop="id" label="库存ID" width="100" />
<el-table-column prop="id" label="库存ID" width="100" />
<el-table-column prop="materialId" label="货物ID" width="100" /> <el-table-column prop="materialId" label="货物ID" width="100" />
<el-table-column prop="batchId" label="批次ID" width="100" /> <el-table-column prop="batchId" label="批次ID" width="100" />
<el-table-column prop="orderId" label="订单ID" width="120" /> <el-table-column prop="orderId" label="订单ID" width="120" />
...@@ -107,31 +106,20 @@ ...@@ -107,31 +106,20 @@
{{ (scope.row.quantity || 0) - (scope.row.lockedQuantity || 0) }} {{ (scope.row.quantity || 0) - (scope.row.lockedQuantity || 0) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="选择数量" width="120"> <!-- 实际数量:填写即视为选中(原选择数量) -->
<el-table-column label="实际数量" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<el-input <el-input
v-model.number="scope.row.selectedQty" v-model.number="scope.row.actualQuantity"
type="number" type="number"
size="mini" size="mini"
min="1" min="1"
:max="(scope.row.quantity || 0) - (scope.row.lockedQuantity || 0)" :max="(scope.row.quantity || 0) - (scope.row.lockedQuantity || 0)"
@input="handleRowQtyInput(scope.row)" @input="handleRowActualQtyInput(scope.row); syncDetails()"
placeholder="输入数量" placeholder="输入数量"
/> />
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="计划件数" width="120">
<template slot-scope="scope">
<el-input
v-model.number="scope.row.plannedPackages"
type="number"
size="mini"
min="0"
@input="handleRowPackagesInput(scope.row)"
placeholder="输入件数"
/>
</template>
</el-table-column>
</el-table> </el-table>
<!-- 选中行的扩展字段填写区域 --> <!-- 选中行的扩展字段填写区域 -->
...@@ -140,8 +128,9 @@ ...@@ -140,8 +128,9 @@
style="margin-top: 10px; padding: 10px; border: 1px solid #e6e6e6; border-radius: 4px;" style="margin-top: 10px; padding: 10px; border: 1px solid #e6e6e6; border-radius: 4px;"
> >
<div style="margin-bottom: 8px; font-weight: 600; color: #1989fa;"> <div style="margin-bottom: 8px; font-weight: 600; color: #1989fa;">
库存【ID: {{ currentSelectedRow.id }}】明细信息 库存明细信息
</div> </div>
<!-- 扩展字段区域保持不变 -->
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="8"> <el-col :span="8">
<el-form-item label="约数" prop="divisor"> <el-form-item label="约数" prop="divisor">
...@@ -150,12 +139,13 @@ ...@@ -150,12 +139,13 @@
placeholder="请输入约数" placeholder="请输入约数"
type="number" type="number"
min="0" min="0"
@input="syncDetails()"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="标签颜色" prop="labelColor"> <el-form-item label="标签颜色" prop="labelColor">
<el-select v-model="currentSelectedRow.labelColor" placeholder="请选择标签颜色"> <el-select v-model="currentSelectedRow.labelColor" placeholder="请选择标签颜色" @change="syncDetails()">
<el-option label="红色" value="1"></el-option> <el-option label="红色" value="1"></el-option>
<el-option label="蓝色" value="2"></el-option> <el-option label="蓝色" value="2"></el-option>
<el-option label="绿色" value="3"></el-option> <el-option label="绿色" value="3"></el-option>
...@@ -163,35 +153,26 @@ ...@@ -163,35 +153,26 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="单价" prop="unitPrice"> <el-form-item label="计划数量" prop="plannedQuantity">
<el-input <el-input
v-model.number="currentSelectedRow.unitPrice" v-model.number="currentSelectedRow.plannedQuantity"
placeholder="请输入单价"
type="number" type="number"
min="0" min="1"
step="0.01" :max="(currentSelectedRow.quantity || 0) - (currentSelectedRow.lockedQuantity || 0)"
@input="handleRowPlannedQtyInput(currentSelectedRow); syncDetails()"
placeholder="输入计划数量"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
</el-row> </el-row>
<el-row :gutter="20" style="margin-top: 10px;"> <el-row :gutter="20" style="margin-top: 10px;">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="收货时间" prop="receivedAt"> <el-form-item label="发货方" prop="shippedBy">
<el-date-picker
v-model="currentSelectedRow.receivedAt"
type="datetime"
value-format="yyyy-MM-dd HH:mm:ss"
placeholder="请选择收货时间"
style="width: 100%"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="收货人" prop="receivedBy">
<el-input <el-input
v-model="currentSelectedRow.receivedBy" v-model="currentSelectedRow.shippedBy"
placeholder="请输入收货人" placeholder="请输入发货方"
@input="syncDetails()"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
...@@ -202,6 +183,7 @@ ...@@ -202,6 +183,7 @@
<el-input <el-input
v-model="currentSelectedRow.voucherNumber" v-model="currentSelectedRow.voucherNumber"
placeholder="请输入凭证号" placeholder="请输入凭证号"
@input="syncDetails()"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
...@@ -214,6 +196,7 @@ ...@@ -214,6 +196,7 @@
placeholder="请输入备注" placeholder="请输入备注"
type="textarea" type="textarea"
rows="2" rows="2"
@input="syncDetails()"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
...@@ -222,7 +205,7 @@ ...@@ -222,7 +205,7 @@
</el-col> </el-col>
</el-row> </el-row>
<!-- 已生成的明细预览 --> <!-- 已生成的明细预览 - 添加库存ID列 -->
<el-row v-if="details.length > 0" style="margin: 10px 0;"> <el-row v-if="details.length > 0" style="margin: 10px 0;">
<el-col :span="24"> <el-col :span="24">
<div style="margin-bottom: 8px; font-weight: 600; color: #1989fa;"> <div style="margin-bottom: 8px; font-weight: 600; color: #1989fa;">
...@@ -233,24 +216,22 @@ ...@@ -233,24 +216,22 @@
border border
size="small" size="small"
max-height="200" max-height="200"
:row-key="item => item.inventoryId"
> >
<el-table-column prop="batchId" label="批次ID" /> <el-table-column prop="inventoryId" label="库存ID" width="100" />
<el-table-column prop="batchCode" label="批次ID" />
<el-table-column prop="warehouseId" label="仓库ID" /> <el-table-column prop="warehouseId" label="仓库ID" />
<el-table-column prop="locationId" label="库位ID" /> <el-table-column prop="locationId" label="库位ID" />
<el-table-column prop="plannedQuantity" label="计划数量" /> <el-table-column prop="plannedQuantity" label="计划数量" />
<el-table-column prop="actualQuantity" label="实际数量" /> <el-table-column prop="actualQuantity" label="实际数量" />
<el-table-column prop="plannedPackages" label="计划件数" />
<el-table-column prop="actualPackages" label="实际件数" />
<el-table-column prop="divisor" label="约数" /> <el-table-column prop="divisor" label="约数" />
<el-table-column prop="unitPrice" label="单价" />
<el-table-column prop="labelColor" label="标签颜色"> <el-table-column prop="labelColor" label="标签颜色">
<template slot-scope="scope"> <template slot-scope="scope">
{{ getLabelColorText(scope.row.labelColor) }} {{ getLabelColorText(scope.row.labelColor) }}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column prop="receivedAt" label="收货时间" />
<el-table-column prop="receivedBy" label="收货人" />
<el-table-column prop="voucherNumber" label="凭证号" /> <el-table-column prop="voucherNumber" label="凭证号" />
<el-table-column prop="shippedBy" label="发货方" />
<el-table-column prop="remark" label="备注" /> <el-table-column prop="remark" label="备注" />
<el-table-column label="操作" width="80"> <el-table-column label="操作" width="80">
<template slot-scope="scope"> <template slot-scope="scope">
...@@ -267,7 +248,7 @@ ...@@ -267,7 +248,7 @@
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button @click.native="handleClose">取消</el-button> <el-button @click.native="handleClose">取消</el-button>
<el-button type="primary" @click.native="handleSubmit">确定</el-button> <el-button type="primary" @click.native="handleSubmit">生成明细</el-button>
</div> </div>
</el-dialog> </el-dialog>
</template> </template>
...@@ -276,7 +257,6 @@ ...@@ -276,7 +257,6 @@
import { listInventoryByMaterialId } from "@/api/inventory/inventory" import { listInventoryByMaterialId } from "@/api/inventory/inventory"
import MaterialSelector from '../../../components/materialsSeletor.vue' import MaterialSelector from '../../../components/materialsSeletor.vue'
// 防抖函数(适配Vue2 this上下文)
function debounce(fn, delay = 500) { function debounce(fn, delay = 500) {
let timer = null let timer = null
return function(...args) { return function(...args) {
...@@ -308,14 +288,13 @@ export default { ...@@ -308,14 +288,13 @@ export default {
}, },
data() { data() {
return { return {
// 仅保留全局字段:货物ID、计划总数量
form: { form: {
materialUuids: '', materialUuids: '',
materialId: '', materialId: '',
totalPlannedQuantity: null, totalPlannedQuantity: null,
itemStatus: '1' // 对应数据库状态:1-待收货 itemStatus: 1
}, },
details: [], details: [],
inventoryList: [], inventoryList: [],
loadingInstance: null, loadingInstance: null,
rules: { rules: {
...@@ -324,26 +303,11 @@ export default { ...@@ -324,26 +303,11 @@ export default {
message: '请选择货物ID', message: '请选择货物ID',
trigger: ['change', 'blur'] trigger: ['change', 'blur']
}] }]
// totalPlannedQuantity: [{
// required: true,
// message: '请输入计划总数量',
// trigger: 'blur',
// type: 'number'
// }, {
// validator: (rule, value, callback) => {
// if (value && value < 1) {
// callback(new Error('计划总数量不能小于1'))
// } else {
// callback()
// }
// },
// trigger: 'blur'
// }]
}, },
openMaterialSelector: false, openMaterialSelector: false,
selectedMaterialId: '', selectedMaterialId: '',
selectedMaterialInfo: null, selectedMaterialInfo: null,
currentSelectedRow: null // 存储当前点击的库存行 currentSelectedRow: null
} }
}, },
created() { created() {
...@@ -356,7 +320,7 @@ export default { ...@@ -356,7 +320,7 @@ export default {
this.form = { ...this.$options.data().form, ...this.initForm } this.form = { ...this.$options.data().form, ...this.initForm }
this.selectedMaterialId = this.form.materialId || '' this.selectedMaterialId = this.form.materialId || ''
this.selectedMaterialInfo = null this.selectedMaterialInfo = null
this.currentSelectedRow = null // 重置选中行 this.currentSelectedRow = null
if (this.form.materialId && this.form.materialId.trim()) { if (this.form.materialId && this.form.materialId.trim()) {
this.handleMaterialIdChange() this.handleMaterialIdChange()
} }
...@@ -377,7 +341,7 @@ export default { ...@@ -377,7 +341,7 @@ export default {
this.form = { ...this.$options.data().form, ...val } this.form = { ...this.$options.data().form, ...val }
this.selectedMaterialId = this.form.materialId || '' this.selectedMaterialId = this.form.materialId || ''
this.selectedMaterialInfo = null this.selectedMaterialInfo = null
this.currentSelectedRow = null // 重置选中行 this.currentSelectedRow = null
if (this.form.materialId && this.form.materialId.trim()) { if (this.form.materialId && this.form.materialId.trim()) {
this.handleMaterialIdChange() this.handleMaterialIdChange()
} }
...@@ -388,7 +352,6 @@ export default { ...@@ -388,7 +352,6 @@ export default {
} }
}, },
methods: { methods: {
// 标签颜色值转文本
getLabelColorText(value) { getLabelColorText(value) {
const colorMap = { const colorMap = {
'1': '红色', '1': '红色',
...@@ -405,165 +368,152 @@ export default { ...@@ -405,165 +368,152 @@ export default {
} }
}, },
async handleMaterialIdChange() { async handleMaterialIdChange() {
const materialId = this.form.materialId?.trim() || '' const materialId = this.form.materialId?.trim() || ''; // 增加分号,避免解析错误
if (!materialId) { if (!materialId) {
this.inventoryList = [] this.inventoryList = [];
this.closeLoading() this.closeLoading();
return return;
} }
try { try {
this.loadingInstance = this.$loading({ this.loadingInstance = this.$loading({
text: '查询中...', text: '查询中...',
target: this.$el, target: this.$el,
lock: true, lock: true,
background: 'rgba(0, 0, 0, 0.7)' background: 'rgba(0, 0, 0, 0.7)'
}) });
const res = await listInventoryByMaterialId(materialId) const res = await listInventoryByMaterialId(materialId); // 增加分号
if (res.code === 200) { if (res.code === 200) {
// 为每个库存行初始化扩展字段 // 按库存ID去重(修复语法:确保Map操作正确)
this.inventoryList = (res.rows || []).map(item => ({ const uniqueInventoryMap = new Map();
...item, (res.rows || []).forEach(item => {
selectedQty: null, if (!uniqueInventoryMap.has(item.id)) {
plannedPackages: null, uniqueInventoryMap.set(item.id, item);
divisor: null, // 约数
labelColor: '', // 标签颜色
unitPrice: null, // 单价
receivedAt: '', // 收货时间
receivedBy: '', // 收货人
voucherNumber: '', // 凭证号
remark: '', // 备注
quantity: item.quantity || 0,
lockedQuantity: item.lockedQuantity || 0
}))
if (this.inventoryList.length === 0) {
this.$message.warning('未查询到该物料的库存信息')
}
} else {
this.inventoryList = []
this.$message.error(res.msg || '查询库存失败')
} }
} catch (error) { });
this.$message.error('查询库存失败:' + (error.message || '网络异常')) const uniqueRows = Array.from(uniqueInventoryMap.values()); // 增加分号
this.inventoryList = []
} finally { this.inventoryList = uniqueRows.map(item => ({
this.closeLoading() ...item,
actualQuantity: null,
plannedQuantity: null,
divisor: null,
labelColor: '',
unitPrice: null,
shippedAt: '',
shippedBy: '',
voucherNumber: '',
remark: '',
quantity: item.quantity || 0,
lockedQuantity: item.lockedQuantity || 0,
batchCode: item.batchId || ''
})); // 增加分号
if (this.inventoryList.length === 0) {
this.$message.warning('未查询到该物料的库存信息');
} }
}, } else {
// 点击库存行触发 - 显示扩展字段填写区域 this.inventoryList = [];
this.$message.error(res.msg || '查询库存失败');
}
} catch (error) {
this.$message.error('查询库存失败:' + (error.message || '网络异常'));
this.inventoryList = [];
} finally {
this.closeLoading();
}
},
handleRowClick(row) { handleRowClick(row) {
if (!row) return
this.currentSelectedRow = row this.currentSelectedRow = row
// 自动选中当前行
this.$refs.inventoryTable.toggleRowSelection(row, true)
}, },
handleRowQtyInput(row) { handleRowActualQtyInput(row) {
if (isNaN(row.selectedQty) || row.selectedQty === '') { if (isNaN(row.actualQuantity) || row.actualQuantity === '') {
row.selectedQty = null row.actualQuantity = null
return return
} }
const availableQty = (row.quantity || 0) - (row.lockedQuantity || 0) const availableQty = (row.quantity || 0) - (row.lockedQuantity || 0)
if (row.selectedQty > availableQty) { if (row.actualQuantity > availableQty) {
this.$message.warning(`选择数量不能超过可用数量${availableQty}`) this.$message.warning(`实际数量不能超过可用数量${availableQty}`)
row.selectedQty = availableQty row.actualQuantity = availableQty
} else if (row.selectedQty < 1) { } else if (row.actualQuantity < 1) {
this.$message.warning('选择数量不能小于1') this.$message.warning('实际数量不能小于1')
row.selectedQty = 1 row.actualQuantity = 1
} }
// 核心改造1:清空其他行的实际数量,确保仅当前行有值
this.inventoryList.forEach(item => {
if (item.id !== row.id) {
item.actualQuantity = null
item.plannedQuantity = null
item.divisor = null
item.labelColor = ''
item.shippedBy = ''
item.voucherNumber = ''
item.remark = ''
}
})
}, },
handleRowPackagesInput(row) { handleRowPlannedQtyInput(row) {
if (isNaN(row.plannedPackages) || row.plannedPackages === '') { if (isNaN(row.plannedQuantity) || row.plannedQuantity === '') {
row.plannedPackages = null row.plannedQuantity = null
return return
} }
if (row.plannedPackages < 0) { const availableQty = (row.quantity || 0) - (row.lockedQuantity || 0)
this.$message.warning('计划件数不能小于0') if (row.plannedQuantity > availableQty) {
row.plannedPackages = 0 this.$message.warning(`计划数量不能超过可用数量${availableQty}`)
row.plannedQuantity = availableQty
} else if (row.plannedQuantity < 1) {
this.$message.warning('计划数量不能小于1')
row.plannedQuantity = 1
} }
}, },
handleSelectionChange(rows) { syncDetails() {
// 过滤已取消选择的行 // 核心修复2:先清空明细,避免重复累加
this.details = this.details.filter(detail => this.details = []
rows.some(row => row.id === detail.inventoryId) // 过滤出仅填写了实际数量的行(此时最多只有一行)
) const validRow = this.inventoryList.find(row => {
// 处理选中行,携带行级扩展字段 if (row.actualQuantity === null || row.actualQuantity === '' || isNaN(row.actualQuantity)) return false
rows.forEach(row => {
// 选择数量为空则跳过
if (row.selectedQty === null || row.selectedQty === '') return
const availableQty = (row.quantity || 0) - (row.lockedQuantity || 0) const availableQty = (row.quantity || 0) - (row.lockedQuantity || 0)
if (row.selectedQty > availableQty || row.selectedQty < 1) { return row.actualQuantity <= availableQty && row.actualQuantity >= 1
this.$message.warning(`行${row.id}的选择数量不合法,请重新输入`) })
row.selectedQty = Math.min(Math.max(row.selectedQty, 1), availableQty)
}
// 校验行级必填字段(可根据实际需求调整)
if (!row.divisor && row.divisor !== 0) {
this.$message.warning(`库存ID:${row.id} 请填写约数`)
return
}
if (!row.labelColor) {
this.$message.warning(`库存ID:${row.id} 请选择标签颜色`)
return
}
if (!row.unitPrice && row.unitPrice !== 0) {
this.$message.warning(`库存ID:${row.id} 请填写单价`)
return
}
if (!row.receivedAt) {
this.$message.warning(`库存ID:${row.id} 请选择收货时间`)
return
}
if (!row.receivedBy) {
this.$message.warning(`库存ID:${row.id} 请填写收货人`)
return
}
const existingIndex = this.details.findIndex(d => d.inventoryId === row.id) if (validRow) {
const newDetail = { const newDetail = {
inventoryId: row.id, inventoryId: validRow.id, // 确保库存ID唯一
materialId: this.form.materialId, materialId: this.form.materialId,
batchId: row.batchId || '', batchCode: validRow.batchCode || '',
warehouseId: row.warehouseId || '', warehouseId: validRow.warehouseId || '',
locationId: row.locationId || '', locationId: validRow.locationId || '',
plannedQuantity: row.selectedQty, plannedQuantity: Number(validRow.plannedQuantity),
actualQuantity: row.selectedQty, actualQuantity: Number(validRow.actualQuantity),
plannedPackages: row.plannedPackages || 0, divisor: Number(validRow.divisor) || 0,
actualPackages: row.plannedPackages || 0, // 实际件数默认等于计划件数 labelColor: Number(validRow.labelColor) || 0,
divisor: row.divisor, // 行级约数 unitPrice: Number(validRow.unitPrice) || 0,
labelColor: row.labelColor, // 行级标签颜色 voucherNumber: validRow.voucherNumber || '',
unitPrice: row.unitPrice, // 行级单价 itemStatus: Number(this.form.itemStatus) || 1,
itemStatus: this.form.itemStatus || '1', shippedAt: validRow.shippedAt,
receivedAt: row.receivedAt, // 行级收货时间 shippedBy: validRow.shippedBy,
receivedBy: row.receivedBy, // 行级收货人 remark: validRow.remark || '',
voucherNumber: row.voucherNumber || '', // 行级凭证号 isUsed: 1,
remark: row.remark || '' // 行级备注 sortNo: 0
} }
if (existingIndex > -1) { this.details.push(newDetail)
this.details.splice(existingIndex, 1, newDetail) }
} else {
this.details.push(newDetail)
}
})
}, },
removeDetail(row) { removeDetail(row) {
this.details = this.details.filter(d => d.inventoryId !== row.inventoryId) this.details = this.details.filter(d => d.inventoryId !== row.inventoryId)
if (this.$refs.inventoryTable && row.id) { const inventoryRow = this.inventoryList.find(item => item.id === row.inventoryId)
const inventoryRow = this.inventoryList.find(item => item.id === row.inventoryId) if (inventoryRow) {
if (inventoryRow) { inventoryRow.actualQuantity = null
this.$refs.inventoryTable.toggleRowSelection(inventoryRow, false) inventoryRow.plannedQuantity = null
// 清空该行的填写内容 inventoryRow.divisor = null
inventoryRow.selectedQty = null inventoryRow.labelColor = ''
inventoryRow.plannedPackages = null inventoryRow.unitPrice = null
inventoryRow.divisor = null inventoryRow.shippedAt = ''
inventoryRow.labelColor = '' inventoryRow.shippedBy = ''
inventoryRow.unitPrice = null inventoryRow.voucherNumber = ''
inventoryRow.receivedAt = '' inventoryRow.remark = ''
inventoryRow.receivedBy = '' if (this.currentSelectedRow && this.currentSelectedRow.id === row.inventoryId) {
inventoryRow.voucherNumber = '' this.currentSelectedRow = null
inventoryRow.remark = ''
// 如果删除的是当前选中行,重置currentSelectedRow
if (this.currentSelectedRow && this.currentSelectedRow.id === row.inventoryId) {
this.currentSelectedRow = null
}
} }
} }
}, },
...@@ -578,12 +528,53 @@ export default { ...@@ -578,12 +528,53 @@ export default {
this.$message.error('表单校验失败,请检查必填项') this.$message.error('表单校验失败,请检查必填项')
return return
} }
this.syncDetails()
if (this.details.length === 0) { if (this.details.length === 0) {
this.$message.error('请选择库存并填写数量生成明细') this.$message.error('请填写实际数量并完善明细信息')
return
}
// 核心改造3:兜底校验 - 检查是否存在重复的inventoryId(防御性编程)
const inventoryIds = this.details.map(d => d.inventoryId)
const uniqueInventoryIds = [...new Set(inventoryIds)]
if (uniqueInventoryIds.length !== inventoryIds.length) {
this.$message.error('发现重复的库存ID明细,请重新选择!')
return return
} }
// 计算实际总数量 let hasError = false
this.details.forEach(detail => {
const row = this.inventoryList.find(r => r.id === detail.inventoryId)
if (!row) return
if (row.divisor === null && row.divisor !== 0) {
this.$message.warning(`库存ID:${row.id} 请填写约数`)
hasError = true
}
if (!row.labelColor) {
this.$message.warning(`库存ID:${row.id} 请选择标签颜色`)
hasError = true
}
if (!row.voucherNumber) {
this.$message.warning(`库存ID:${row.id} 请填写凭证号`)
hasError = true
}
if (!row.shippedBy) {
this.$message.warning(`库存ID:${row.id} 请填写发货方`)
hasError = true
}
if (!row.plannedQuantity) {
this.$message.warning(`库存ID:${row.id} 请填写计划数量`)
hasError = true
}
if (!row.actualQuantity) {
this.$message.warning(`库存ID:${row.id} 请填写实际数量`)
hasError = true
}
})
if (hasError) return
const totalActual = this.details.reduce((sum, d) => sum + (d.actualQuantity || 0), 0) const totalActual = this.details.reduce((sum, d) => sum + (d.actualQuantity || 0), 0)
if (this.form.totalPlannedQuantity && this.form.totalPlannedQuantity !== totalActual) { if (this.form.totalPlannedQuantity && this.form.totalPlannedQuantity !== totalActual) {
try { try {
...@@ -613,7 +604,7 @@ export default { ...@@ -613,7 +604,7 @@ export default {
this.selectedMaterialId = '' this.selectedMaterialId = ''
this.selectedMaterialInfo = null this.selectedMaterialInfo = null
this.openMaterialSelector = false this.openMaterialSelector = false
this.currentSelectedRow = null // 重置选中行 this.currentSelectedRow = null
if (this.$refs.detailForm) { if (this.$refs.detailForm) {
this.$refs.detailForm.resetFields() this.$refs.detailForm.resetFields()
} }
...@@ -683,7 +674,6 @@ export default { ...@@ -683,7 +674,6 @@ export default {
min-height: 500px; min-height: 500px;
} }
/* 修复模态框遮罩层点击穿透问题 */
/deep/ .el-dialog__wrapper { /deep/ .el-dialog__wrapper {
.el-modal__mask { .el-modal__mask {
pointer-events: auto !important; pointer-events: auto !important;
......
...@@ -122,13 +122,20 @@ ...@@ -122,13 +122,20 @@
</el-row> </el-row>
<!-- 主表格 --> <!-- 主表格 -->
<el-table v-loading="loading" :data="ordersList" @selection-change="handleSelectionChange"> <el-table
ref="mainTable"
v-loading="loading"
:data="ordersList"
@selection-change="handleSelectionChange"
:key="tableKey"
>
<el-table-column type="selection" width="55" align="center" /> <el-table-column type="selection" width="55" align="center" />
<el-table-column label="出库单号" align="center" prop="orderId" width="150" /> <el-table-column label="出库单号" align="center" prop="orderId" width="150" />
<el-table-column label="系统编号" align="center" prop="systemNo" width="150" /> <el-table-column label="系统编号" align="center" prop="systemNo" width="150" />
<el-table-column label="入库类型" align="center" prop="orderTypeId" width="120"> <el-table-column label="入库类型" align="center" prop="orderTypeId" width="120">
<template slot-scope="scope"> <template slot-scope="scope">
<dict-tag :options="dict.type.inbound_order_type" :value="scope.row.orderTypeId"/> <dict-tag v-if="dict.type.inbound_order_type" :options="dict.type.inbound_order_type" :value="scope.row.orderTypeId"/>
<span v-else>-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="批次ID" align="center" prop="batchCode" width="120" /> <el-table-column label="批次ID" align="center" prop="batchCode" width="120" />
...@@ -136,7 +143,8 @@ ...@@ -136,7 +143,8 @@
<el-table-column label="货主ID" align="center" prop="ownerId" width="100" /> <el-table-column label="货主ID" align="center" prop="ownerId" width="100" />
<el-table-column label="订单状态" align="center" prop="orderStatus" width="150"> <el-table-column label="订单状态" align="center" prop="orderStatus" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<dict-tag :options="dict.type.inbound_order_status" :value="scope.row.orderStatus"/> <dict-tag v-if="dict.type.inbound_order_status" :options="dict.type.inbound_order_status" :value="scope.row.orderStatus"/>
<span v-else>-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="出库日期" align="center" prop="inboundDate" width="150"> <el-table-column label="出库日期" align="center" prop="inboundDate" width="150">
...@@ -149,7 +157,7 @@ ...@@ -149,7 +157,7 @@
<el-table-column label="实际量" align="center" prop="totalActualQuantity" width="100" /> <el-table-column label="实际量" align="center" prop="totalActualQuantity" width="100" />
<el-table-column label="总件数" align="center" prop="totalPackages" width="100" /> <el-table-column label="总件数" align="center" prop="totalPackages" width="100" />
<el-table-column label="备注" align="center" prop="remark" width="150" /> <el-table-column label="备注" align="center" prop="remark" width="150" />
<el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120"> <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="180">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
size="mini" size="mini"
...@@ -161,6 +169,13 @@ ...@@ -161,6 +169,13 @@
<el-button <el-button
size="mini" size="mini"
type="text" type="text"
icon="el-icon-send"
@click="handleShip(scope.row)"
v-hasPermi="['inventory:orders:edit']"
>出货</el-button>
<el-button
size="mini"
type="text"
icon="el-icon-delete" icon="el-icon-delete"
@click="handleDelete(scope.row)" @click="handleDelete(scope.row)"
v-hasPermi="['inventory:orders:remove']" v-hasPermi="['inventory:orders:remove']"
...@@ -266,7 +281,6 @@ ...@@ -266,7 +281,6 @@
<el-divider content-position="center">入库单明细信息</el-divider> <el-divider content-position="center">入库单明细信息</el-divider>
<el-row :gutter="10" class="mb8"> <el-row :gutter="10" class="mb8">
<el-col :span="1.5"> <el-col :span="1.5">
<!-- 点击该按钮打开子组件弹窗 -->
<el-button type="primary" icon="el-icon-plus" size="mini" @click="openDetailDialog">添加</el-button> <el-button type="primary" icon="el-icon-plus" size="mini" @click="openDetailDialog">添加</el-button>
</el-col> </el-col>
<el-col :span="1.5"> <el-col :span="1.5">
...@@ -274,37 +288,45 @@ ...@@ -274,37 +288,45 @@
</el-col> </el-col>
</el-row> </el-row>
<el-table <el-table
:data="inboundOrderItemsList" :data="outboundOrderItemsList"
:row-class-name="rowInboundOrderItemsIndex" :row-class-name="rowInboundOrderItemsIndex"
@selection-change="handleInboundOrderItemsSelectionChange" @selection-change="handleInboundOrderItemsSelectionChange"
ref="inboundOrderItems" ref="inboundOrderItems"
border border
style="width: 100%;" style="width: 100%;"
v-if="outboundOrderItemsList.length > 0"
:row-key="item => item.inventoryId"
> >
<el-table-column type="selection" width="50" align="center" /> <el-table-column type="selection" width="50" align="center" />
<el-table-column label="序号" align="center" prop="index" width="50"/> <el-table-column label="序号" align="center" prop="index" width="50"/>
<el-table-column prop="inventoryId" label="库存ID" width="100" />
<el-table-column label="货物ID" prop="materialId" width="150" /> <el-table-column label="货物ID" prop="materialId" width="150" />
<el-table-column label="批次ID" prop="batchId" width="150" /> <el-table-column label="批次ID" prop="batchCode" width="150" />
<el-table-column label="仓库ID" prop="warehouseId" width="150" /> <el-table-column label="仓库ID" prop="warehouseId" width="150" />
<el-table-column label="库位ID" prop="locationId" width="150" /> <el-table-column label="库位ID" prop="locationId" width="150" />
<el-table-column label="计划数量" prop="plannedQuantity" width="150" /> <el-table-column label="计划数量" prop="plannedQuantity" width="150" />
<el-table-column label="实际数量" prop="actualQuantity" width="150" /> <el-table-column label="实际数量" prop="actualQuantity" width="150" />
<el-table-column label="计划件数" prop="plannedPackages" width="150" />
<el-table-column label="实际件数" prop="actualPackages" width="150" />
<el-table-column label="约数" prop="divisor" width="150" /> <el-table-column label="约数" prop="divisor" width="150" />
<el-table-column label="标签颜色" prop="labelColor" width="150" /> <el-table-column label="标签颜色" prop="labelColor" width="150">
<template slot-scope="scope">
{{ getLabelColorText(scope.row.labelColor) }}
</template>
</el-table-column>
<el-table-column label="单价" prop="unitPrice" width="150" /> <el-table-column label="单价" prop="unitPrice" width="150" />
<el-table-column label="凭证号" prop="voucherNumber" width="150" />
<el-table-column label="状态" prop="itemStatus" width="150"> <el-table-column label="状态" prop="itemStatus" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<dict-tag :options="dict.type.inbound_order_item_status" :value="scope.row.itemStatus"/> <dict-tag v-if="dict.type.inbound_order_item_status" :options="dict.type.inbound_order_item_status" :value="scope.row.itemStatus"/>
<span v-else>-</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="收货时间" prop="receivedAt" width="150"> <el-table-column label="发货时间" prop="shippedAt" width="150">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{ parseTime(scope.row.receivedAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span> <span>{{ parseTime(scope.row.shippedAt, '{y}-{m}-{d} {h}:{i}:{s}') }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="收货人" prop="receivedBy" width="150" /> <el-table-column label="发货方" prop="shippedBy" width="150" />
<el-table-column label="备注" prop="remark" width="150" />
<el-table-column label="操作" align="center" width="80"> <el-table-column label="操作" align="center" width="80">
<template slot-scope="scope"> <template slot-scope="scope">
<el-button <el-button
...@@ -316,6 +338,9 @@ ...@@ -316,6 +338,9 @@
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
<div v-else class="empty-tip" style="text-align: center; padding: 20px; color: #999;">
暂无明细数据,请点击添加按钮添加
</div>
</el-form> </el-form>
<div slot="footer" class="dialog-footer"> <div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm"> </el-button> <el-button type="primary" @click="submitForm"> </el-button>
...@@ -323,7 +348,7 @@ ...@@ -323,7 +348,7 @@
</div> </div>
</el-dialog> </el-dialog>
<!-- 明细项添加/编辑子组件弹窗OutboundOrderFormWithItems --> <!-- 明细项添加/编辑子组件弹窗 -->
<OutboundOrderFormWithItems <OutboundOrderFormWithItems
:title="detailDialogTitle" :title="detailDialogTitle"
:open="detailDialogOpen" :open="detailDialogOpen"
...@@ -336,18 +361,19 @@ ...@@ -336,18 +361,19 @@
</template> </template>
<script> <script>
import { listOrders, getOrders, delOrders, addOrders, updateOrders } from "@/api/inventory/orders" import { listOrders, getOrders, delOrders, addOrders, updateOrders, ship } from "@/api/inventory/orders"
// 导入明细子组件
import OutboundOrderFormWithItems from './OutboundOrderFormWithItems.vue' import OutboundOrderFormWithItems from './OutboundOrderFormWithItems.vue'
export default { export default {
name: "Orders", name: "Orders",
dicts: ['inbound_order_status', 'inbound_order_type', 'inbound_order_item_status'], dicts: ['inbound_order_status', 'inbound_order_type', 'inbound_order_item_status'],
components: { components: {
OutboundOrderFormWithItems // 注册子组件 OutboundOrderFormWithItems
}, },
data() { data() {
return { return {
// 添加tableKey解决tableId渲染问题
tableKey: 1,
// 遮罩层 // 遮罩层
loading: true, loading: true,
// 选中数组 // 选中数组
...@@ -366,31 +392,34 @@ export default { ...@@ -366,31 +392,34 @@ export default {
title: "", title: "",
// 主弹窗是否显示 // 主弹窗是否显示
open: false, open: false,
// 明细表格数据 // 明细列表
inboundOrderItemsList: [], outboundOrderItemsList: [],
// 选中的明细行 // 选中的明细行
selectedInboundOrderItems: [], selectedInboundOrderItems: [],
// 明细子弹窗相关 // 明细子弹窗相关
detailDialogOpen: false, // 子弹窗是否显示 detailDialogOpen: false,
detailDialogTitle: "新增明细项", // 子弹窗标题 detailDialogTitle: "新增明细项",
currentDetailItem: { currentDetailItem: {
materialUuids: '', // 存储物料选择器返回的materialCodes inventoryId: '',
materialUuids: '',
materialId: '', materialId: '',
batchId: '', batchCode: '',
warehouseId: '', warehouseId: '',
locationId: '', locationId: '',
plannedQuantity: '', plannedQuantity: '',
actualQuantity: '', actualQuantity: '',
plannedPackages: '',
actualPackages: '',
divisor: '', divisor: '',
labelColor: '', labelColor: '',
unitPrice: '', unitPrice: '',
itemStatus: 'pending', voucherNumber: '',
receivedAt: '', itemStatus: 1,
receivedBy: '' shippedAt: '',
}, // 当前编辑的明细项 shippedBy: '',
isEditDetail: false, // 标记是否为编辑明细 isUsed: 1,
sortNo: 0,
remark: ''
},
isEditDetail: false,
// 查询参数 // 查询参数
queryParams: { queryParams: {
pageNum: 1, pageNum: 1,
...@@ -423,30 +452,59 @@ export default { ...@@ -423,30 +452,59 @@ export default {
} }
}, },
created() { created() {
this.getList() // 延迟加载避免初始化渲染问题
this.$nextTick(() => {
this.getList()
})
}, },
methods: { methods: {
// ========== 明细子弹窗相关方法 ========== // 核心出货方法
async handleShip(row) {
try {
// 调用ship接口提交数据到后端
await ship(row)
// 提示成功并刷新列表
this.$modal.msgSuccess("出货操作成功,数据已提交到后端")
this.getList()
} catch (error) {
// 错误处理
this.$modal.msgError(error.msg || "出货操作失败")
}
},
// 标签颜色值转文本
getLabelColorText(value) {
const colorMap = {
'1': '红色',
'2': '蓝色',
'3': '绿色',
'4': '黄色'
}
return colorMap[value] || '-'
},
// 打开明细子弹窗(新增) // 打开明细子弹窗(新增)
openDetailDialog() { openDetailDialog() {
this.isEditDetail = false this.isEditDetail = false
this.detailDialogTitle = "新增明细项" this.detailDialogTitle = "新增明细项"
this.currentDetailItem = { this.currentDetailItem = {
materialUuids: '', // 初始化materialUuids(接收materialCodes) inventoryId: '',
materialUuids: '',
materialId: '', materialId: '',
batchId: '', batchCode: '',
warehouseId: '', warehouseId: this.form.warehouseId || '',
locationId: '', locationId: '',
plannedQuantity: '', plannedQuantity: '',
actualQuantity: '', actualQuantity: '',
plannedPackages: '',
actualPackages: '',
divisor: '', divisor: '',
labelColor: '', labelColor: '',
unitPrice: '', unitPrice: '',
itemStatus: 'pending', // 默认状态 voucherNumber: '',
receivedAt: '', itemStatus: 1,
receivedBy: '' shippedAt: '',
shippedBy: '',
isUsed: 1,
sortNo: 0,
remark: ''
} }
this.detailDialogOpen = true this.detailDialogOpen = true
}, },
...@@ -454,73 +512,108 @@ export default { ...@@ -454,73 +512,108 @@ export default {
editDetailItem(row) { editDetailItem(row) {
this.isEditDetail = true this.isEditDetail = true
this.detailDialogTitle = "编辑明细项" this.detailDialogTitle = "编辑明细项"
// 兼容materialUuids:优先取row.materialUuids,无则用materialId(适配返回的materialCodes)
this.currentDetailItem = { this.currentDetailItem = {
...row, ...row,
materialUuids: row.materialUuids || row.materialId || '' inventoryId: row.inventoryId || '',
} materialUuids: row.materialId || '',
divisor: row.divisor || 0,
itemStatus: row.itemStatus || 1,
labelColor: row.labelColor || 0,
plannedQuantity: row.plannedQuantity || 0,
actualQuantity: row.actualQuantity || 0,
remark: row.remark || ''
}
this.detailDialogOpen = true this.detailDialogOpen = true
}, },
// 接收子组件提交的明细数据(核心修改:适配materialCodes返回格式 // 接收子组件提交的明细数据(核心修复:新增去重逻辑
handleDetailSubmit(details) { handleDetailSubmit(details) {
// 兼容子组件返回格式:如果是materialCodes结构,提取第一个值赋值给materialId
const formatDetail = (item) => {
// 处理物料选择器返回的materialCodes数组
if (item.materialUuids && Array.isArray(item.materialUuids)) {
item.materialId = item.materialUuids[0] || '' // 单选取第一个值
item.materialUuids = item.materialUuids[0] || '' // 同步更新materialUuids
}
// 兼容子组件返回的原始格式
return item
}
// 统一转为数组处理
const detailList = Array.isArray(details) ? details : [details] const detailList = Array.isArray(details) ? details : [details]
// 格式化每条明细的物料字段
const formattedList = detailList.map(item => formatDetail(item))
if (this.isEditDetail) { if (this.isEditDetail) {
// 编辑模式:替换原有单条数据 // 编辑模式
const editIndex = this.inboundOrderItemsList.findIndex(item => item.index === this.currentDetailItem.index) const editIndex = this.outboundOrderItemsList.findIndex(item => item.index === this.currentDetailItem.index)
if (editIndex > -1) { if (editIndex > -1) {
this.inboundOrderItemsList.splice(editIndex, 1, { this.outboundOrderItemsList.splice(editIndex, 1, {
...formattedList[0], ...detailList[0],
index: this.currentDetailItem.index index: this.currentDetailItem.index,
orderId: this.form.id || this.form.orderId,
inventoryId: detailList[0].inventoryId || '',
itemStatus: Number(detailList[0].itemStatus) || 1,
labelColor: Number(detailList[0].labelColor) || 0,
divisor: Number(detailList[0].divisor) || 0,
plannedQuantity: Number(detailList[0].plannedQuantity) || 0,
actualQuantity: Number(detailList[0].actualQuantity) || 0,
isUsed: 1,
sortNo: 0,
remark: detailList[0].remark || ''
}) })
} }
this.$message.success("编辑明细成功") this.$message.success("编辑明细成功")
} else { } else {
// 新增模式:批量添加多条明细 // 新增模式:按库存ID去重,避免重复添加
const newDetails = formattedList.map((item, idx) => { const existingInventoryIds = new Set(this.outboundOrderItemsList.map(item => item.inventoryId))
const newIndex = this.inboundOrderItemsList.length + idx + 1 // 过滤已存在的库存ID
return { ...item, index: newIndex } const newDetails = detailList
}) .filter(item => item.inventoryId && !existingInventoryIds.has(item.inventoryId))
this.inboundOrderItemsList = [...this.inboundOrderItemsList, ...newDetails] .map((item, idx) => {
const newIndex = this.outboundOrderItemsList.length + idx + 1
return {
...item,
index: newIndex,
orderId: this.form.id || this.form.orderId,
inventoryId: item.inventoryId || '',
itemStatus: Number(item.itemStatus) || 1,
labelColor: Number(item.labelColor) || 0,
divisor: Number(item.divisor) || 0,
plannedQuantity: Number(item.plannedQuantity) || 0,
actualQuantity: Number(item.actualQuantity) || 0,
isUsed: 1,
sortNo: 0,
remark: item.remark || ''
}
})
// 自动计算主表总数量 // 无新数据则提示
if (newDetails.length === 0) {
this.$message.warning("该库存明细已存在,无法重复添加")
this.detailDialogOpen = false
return
}
this.outboundOrderItemsList = [...this.outboundOrderItemsList, ...newDetails]
this.calcTotalQuantity() this.calcTotalQuantity()
this.$message.success(`成功新增${newDetails.length}条明细`) this.$message.success(`成功新增${newDetails.length}条明细`)
} }
this.detailDialogOpen = false this.detailDialogOpen = false
// 更新tableKey触发重新渲染
this.tableKey += 1
}, },
// 计算主表总数量
// 自动计算主表的计划总量/实际总量/总件数
calcTotalQuantity() { calcTotalQuantity() {
const totalPlanned = this.inboundOrderItemsList.reduce((sum, item) => sum + (Number(item.plannedQuantity) || 0), 0) const totalPlanned = this.outboundOrderItemsList.reduce((sum, item) => {
const totalActual = this.inboundOrderItemsList.reduce((sum, item) => sum + (Number(item.actualQuantity) || 0), 0) const qty = item.plannedQuantity !== null ? Number(item.plannedQuantity) : 0
const totalPackages = this.inboundOrderItemsList.reduce((sum, item) => sum + (Number(item.actualPackages) || 0), 0) return sum + qty
}, 0)
const totalActual = this.outboundOrderItemsList.reduce((sum, item) => {
const qty = item.actualQuantity !== null ? Number(item.actualQuantity) : 0
return sum + qty
}, 0)
const totalPackages = this.outboundOrderItemsList.reduce((sum, item) => {
const divisor = item.divisor !== null ? Number(item.divisor) : 1
const actualQty = item.actualQuantity !== null ? Number(item.actualQuantity) : 0
return sum + Math.ceil(actualQty / divisor)
}, 0)
this.form.totalPlannedQuantity = totalPlanned this.form.totalPlannedQuantity = totalPlanned
this.form.totalActualQuantity = totalActual this.form.totalActualQuantity = totalActual
this.form.totalPackages = totalPackages this.form.totalPackages = totalPackages
}, },
// ========== 明细表格相关方法 ==========
// 生成明细表格行序号 // 生成明细表格行序号
rowInboundOrderItemsIndex({ row, rowIndex }) { rowInboundOrderItemsIndex({ row, rowIndex }) {
if (!row.index) row.index = rowIndex + 1 if (row.index === undefined || row.index === null) {
row.index = rowIndex + 1
}
}, },
// 明细表格选择事件 // 明细表格选择事件
handleInboundOrderItemsSelectionChange(val) { handleInboundOrderItemsSelectionChange(val) {
...@@ -532,30 +625,32 @@ export default { ...@@ -532,30 +625,32 @@ export default {
this.$message.warning('请选择要删除的明细行') this.$message.warning('请选择要删除的明细行')
return return
} }
// 获取选中行索引并倒序删除
const selectedIndexes = this.selectedInboundOrderItems.map(item => const selectedIndexes = this.selectedInboundOrderItems.map(item =>
this.inboundOrderItemsList.findIndex(row => row.index === item.index) this.outboundOrderItemsList.findIndex(row => row.index === item.index)
) )
selectedIndexes.sort((a, b) => b - a).forEach(index => { selectedIndexes.sort((a, b) => b - a).forEach(index => {
this.inboundOrderItemsList.splice(index, 1) this.outboundOrderItemsList.splice(index, 1)
}) })
// 重新更新序号 // 重新排序序号
this.inboundOrderItemsList.forEach((row, index) => { this.outboundOrderItemsList.forEach((row, index) => {
row.index = index + 1 row.index = index + 1
}) })
// 重新计算总数量
this.calcTotalQuantity() this.calcTotalQuantity()
this.$message.success('明细行删除成功') this.$message.success('明细行删除成功')
}, },
// ========== 主表格/表单相关方法 ==========
/** 查询出库单主列表 */ /** 查询出库单主列表 */
getList() { getList() {
this.loading = true this.loading = true
listOrders(this.queryParams).then(response => { listOrders(this.queryParams).then(response => {
this.ordersList = response.rows this.ordersList = response.rows || []
this.total = response.total this.total = response.total || 0
this.loading = false
// 更新tableKey解决渲染问题
this.tableKey += 1
}).catch(() => {
this.loading = false this.loading = false
this.ordersList = []
this.total = 0
}) })
}, },
// 取消按钮 // 取消按钮
...@@ -587,10 +682,12 @@ export default { ...@@ -587,10 +682,12 @@ export default {
updateTime: null, updateTime: null,
updateUserCode: null updateUserCode: null
} }
// 重置明细表格 this.outboundOrderItemsList = []
this.inboundOrderItemsList = []
this.selectedInboundOrderItems = [] this.selectedInboundOrderItems = []
this.resetForm("form") // 检查ref存在性
if (this.$refs.form) {
this.resetForm("form")
}
}, },
/** 搜索按钮操作 */ /** 搜索按钮操作 */
handleQuery() { handleQuery() {
...@@ -599,7 +696,10 @@ export default { ...@@ -599,7 +696,10 @@ export default {
}, },
/** 重置按钮操作 */ /** 重置按钮操作 */
resetQuery() { resetQuery() {
this.resetForm("queryForm") // 检查ref存在性
if (this.$refs.queryForm) {
this.resetForm("queryForm")
}
this.handleQuery() this.handleQuery()
}, },
// 多选框选中数据 // 多选框选中数据
...@@ -614,39 +714,95 @@ export default { ...@@ -614,39 +714,95 @@ export default {
this.open = true this.open = true
this.title = "添加出库单" this.title = "添加出库单"
}, },
/** 修改按钮操作 */ /** 修改按钮操作(修复:加载明细时去重) */
handleUpdate(row) { handleUpdate(row) {
this.reset() this.reset()
const id = row.id || this.ids const id = row.id || this.ids
getOrders(id).then(response => { getOrders(id).then(response => {
this.form = response.data this.form = response.data || {}
// 如果有明细数据,初始化明细表格 if (response.data && response.data.outboundOrderItemsList && Array.isArray(response.data.outboundOrderItemsList)) {
if (response.data.items) { // 按库存ID去重
this.inboundOrderItemsList = response.data.items.map((item, index) => ({ const uniqueItemsMap = new Map()
response.data.outboundOrderItemsList.forEach(item => {
if (item.inventoryId && !uniqueItemsMap.has(item.inventoryId)) {
uniqueItemsMap.set(item.inventoryId, item)
}
})
const uniqueItems = Array.from(uniqueItemsMap.values())
this.outboundOrderItemsList = uniqueItems.map((item, index) => ({
...item, ...item,
// 兼容materialUuids:适配物料选择器返回的materialCodes格式 index: index + 1,
materialUuids: item.materialUuids || item.materialId || '', inventoryId: item.inventoryId || '',
index: index + 1 divisor: item.divisor !== null ? Number(item.divisor) : 0,
itemStatus: item.itemStatus !== null ? Number(item.itemStatus) : 1,
labelColor: item.labelColor !== null ? Number(item.labelColor) : 0,
plannedQuantity: item.plannedQuantity !== null ? Number(item.plannedQuantity) : 0,
actualQuantity: item.actualQuantity !== null ? Number(item.actualQuantity) : 0,
isUsed: item.isUsed !== null ? Number(item.isUsed) : 1,
sortNo: item.sortNo !== null ? Number(item.sortNo) : 0,
materialUuids: item.materialId || '',
warehouseId: item.warehouseId || '',
locationId: item.locationId || '',
voucherNumber: item.voucherNumber || '',
shippedAt: item.shippedAt || '',
shippedBy: item.shippedBy || '',
remark: item.remark || '',
orderId: response.data.id
})) }))
// 计算总数量
this.calcTotalQuantity() this.calcTotalQuantity()
} }
this.open = true this.open = true
this.title = "修改出库单" this.title = "修改出库单"
}) })
}, },
/** 提交按钮 */ /** 提交按钮(修复:提交前最后去重) */
submitForm() { submitForm() {
// 检查表单ref存在性
if (!this.$refs.form) {
this.$message.error('表单初始化失败,请重试')
return
}
this.$refs["form"].validate(async (valid) => { this.$refs["form"].validate(async (valid) => {
if (valid) { if (valid) {
// 组装完整数据(主表+明细) if (this.outboundOrderItemsList.length === 0) {
this.$message.warning('请至少添加一条明细数据')
return
}
// 提交前按库存ID去重
const uniqueDetailsMap = new Map()
this.outboundOrderItemsList.forEach(item => {
if (item.inventoryId && !uniqueDetailsMap.has(item.inventoryId)) {
uniqueDetailsMap.set(item.inventoryId, item)
}
})
const uniqueDetails = Array.from(uniqueDetailsMap.values())
const submitData = { const submitData = {
...this.form, ...this.form,
items: this.inboundOrderItemsList.map(item => { outboundOrderItemsList: uniqueDetails.map(item => {
const { index, ...rest } = item // 剔除序号 const { index, materialUuids, ...rest } = item
// 提交时确保materialId是单选的物料编码(从materialUuids/原materialId取值) return {
rest.materialId = rest.materialUuids || rest.materialId || '' ...rest,
return rest orderId: this.form.id || this.form.orderId,
inventoryId: rest.inventoryId || '',
materialId: rest.materialId || '',
batchCode: rest.batchCode || '',
warehouseId: rest.warehouseId || '',
locationId: rest.locationId || '',
plannedQuantity: Number(rest.plannedQuantity) || 0,
actualQuantity: Number(rest.actualQuantity) || 0,
divisor: Number(rest.divisor) || 0,
labelColor: Number(rest.labelColor) || 0,
voucherNumber: rest.voucherNumber || '',
itemStatus: Number(rest.itemStatus) || 1,
shippedAt: rest.shippedAt || '',
shippedBy: rest.shippedBy || '',
remark: rest.remark || '',
isUsed: 1,
sortNo: Number(rest.sortNo) || 0
}
}) })
} }
try { try {
...@@ -660,8 +816,13 @@ export default { ...@@ -660,8 +816,13 @@ export default {
this.open = false this.open = false
this.getList() this.getList()
} catch (error) { } catch (error) {
this.$modal.msgError(error.msg || "操作失败") // 【关键】捕获异常时弹窗(覆盖接口报错场景)
} if (error !== 'cancel') { // 排除用户点击取消的情况
// 优先用后端返回的msg,没有则显示默认文案
const errorMsg = error?.response?.data?.msg || '库存被修改请重新确认';
this.$modal.msgError(errorMsg); // 核心弹窗代码(若依风格错误弹窗)
}
}
} }
}) })
}, },
...@@ -703,4 +864,9 @@ export default { ...@@ -703,4 +864,9 @@ export default {
.el-table { .el-table {
--el-table-row-hover-bg-color: #f8f9fa; --el-table-row-hover-bg-color: #f8f9fa;
} }
/* 空数据提示样式 */
.empty-tip {
color: #999;
font-size: 14px;
}
</style> </style>
\ No newline at end of file
...@@ -4,7 +4,7 @@ import java.util.List; ...@@ -4,7 +4,7 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.common.core.domain.entity.Materials; import com.ruoyi.inventory.domain.InboundOrderItems;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
...@@ -19,7 +19,6 @@ import com.ruoyi.common.annotation.Log; ...@@ -19,7 +19,6 @@ import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType; import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.inventory.domain.InboundOrderItems;
import com.ruoyi.inventory.service.IInboundOrderItemsService; import com.ruoyi.inventory.service.IInboundOrderItemsService;
import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
......
...@@ -118,6 +118,10 @@ ...@@ -118,6 +118,10 @@
<groupId>javax.servlet</groupId> <groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId> <artifactId>javax.servlet-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
</dependencies> </dependencies>
......
package com.ruoyi.common.annotation;
import java.lang.annotation.*;
/**
* 若依框架适配 - 方法串行执行注解
* 标记该注解的方法,同一分组内串行执行,不同分组并行
*
* @author RuoYi
*/
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SerialExecution {
/**
* 串行分组(默认空,全局串行)
*/
String group() default "";
/**
* 是否公平锁(按线程等待顺序执行)
*/
boolean fair() default false;
}
\ No newline at end of file
package com.ruoyi.common.aspectj;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.utils.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 若依框架适配 - 串行执行注解切面
* 参考若依 SysLogAspect 实现风格
*
* @author RuoYi
*/
@Aspect
@Component
public class SerialExecutionAspect {
/**
* 分组锁缓存:key=分组名,value=锁对象
*/
private final Map<String, Lock> groupLockCache = new ConcurrentHashMap<>();
/**
* 切入点:拦截所有标记@SerialExecution的方法
*/
@Pointcut("@annotation(com.ruoyi.common.annotation.SerialExecution)")
public void serialExecutionPointCut() {
}
/**
* 环绕通知:加锁执行,确保串行
*/
@Around("serialExecutionPointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
// 1. 获取方法注解信息(参考若依日志切面的参数解析方式)
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SerialExecution serialAnnotation = method.getAnnotation(SerialExecution.class);
if (serialAnnotation == null) {
return joinPoint.proceed();
}
// 2. 解析分组(默认空=全局分组)
String group = StringUtils.trimToEmpty(serialAnnotation.group());
boolean fair = serialAnnotation.fair();
// 3. 获取/创建分组锁(复用若依 StringUtils 工具类)
Lock lock = groupLockCache.computeIfAbsent(group, k -> new ReentrantLock(fair));
// 4. 加锁执行(try-finally 确保锁释放,避免死锁)
try {
lock.lock();
// 执行原方法(若依业务方法的执行逻辑)
return joinPoint.proceed();
} finally {
lock.unlock();
// 可选:若依日志记录(可接入若依的日志框架)
// LogUtils.info("串行方法执行完成,分组:{},方法:{}", group, method.getName());
}
}
}
\ No newline at end of file
...@@ -78,7 +78,16 @@ public class OutboundOrderItemsController extends BaseController ...@@ -78,7 +78,16 @@ public class OutboundOrderItemsController extends BaseController
@PostMapping @PostMapping
public AjaxResult add(@RequestBody OutboundOrderItems outboundOrderItems) public AjaxResult add(@RequestBody OutboundOrderItems outboundOrderItems)
{ {
return toAjax(outboundOrderItemsService.insertOutboundOrderItems(outboundOrderItems)); try {
// 调用业务层校验+插入逻辑
outboundOrderItemsService.insertOutboundOrderItems(outboundOrderItems);
// 校验通过:返回成功(若依标准成功响应)
return success("新增出库单明细成功");
} catch (Exception e) {
// 校验失败:捕获异常,返回"库存被修改请重新确认"(前端弹窗用)
logger.error("新增出库单明细失败", e);
return error("库存被修改请重新确认");
}
} }
/** /**
...@@ -89,9 +98,19 @@ public class OutboundOrderItemsController extends BaseController ...@@ -89,9 +98,19 @@ public class OutboundOrderItemsController extends BaseController
@PutMapping @PutMapping
public AjaxResult edit(@RequestBody OutboundOrderItems outboundOrderItems) public AjaxResult edit(@RequestBody OutboundOrderItems outboundOrderItems)
{ {
return toAjax(outboundOrderItemsService.updateOutboundOrderItems(outboundOrderItems)); try {
// 调用业务层校验+插入逻辑
outboundOrderItemsService.updateOutboundOrderItems(outboundOrderItems);
// 校验通过:返回成功(若依标准成功响应)
return success("新增出库单明细成功");
} catch (Exception e) {
// 校验失败:捕获异常,返回"库存被修改请重新确认"(前端弹窗用)
logger.error("新增出库单明细失败", e);
return error("库存被修改请重新确认");
}
} }
/** /**
* 删除出库单明细 * 删除出库单明细
*/ */
......
...@@ -2,6 +2,8 @@ package com.ruoyi.inventory.controller; ...@@ -2,6 +2,8 @@ package com.ruoyi.inventory.controller;
import java.util.List; import java.util.List;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.ruoyi.inventory.domain.Inventory;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
...@@ -70,6 +72,17 @@ public class OutboundOrdersController extends BaseController ...@@ -70,6 +72,17 @@ public class OutboundOrdersController extends BaseController
} }
/** /**
* 出货
*/
@PreAuthorize("@ss.hasPermi('inventory:inventory:edit')")
@Log(title = "出货", businessType = BusinessType.UPDATE)
@PostMapping("/ship")
public AjaxResult Ship(@RequestBody OutboundOrders outboundOrders )
{
return toAjax(outboundOrdersService.ship(outboundOrders));
}
/**
* 新增出库单主 * 新增出库单主
*/ */
@PreAuthorize("@ss.hasPermi('inventory:orders:add')") @PreAuthorize("@ss.hasPermi('inventory:orders:add')")
......
...@@ -40,6 +40,10 @@ public class OutboundOrderItems extends BaseEntity ...@@ -40,6 +40,10 @@ public class OutboundOrderItems extends BaseEntity
@Excel(name = "库位ID 检索条件") @Excel(name = "库位ID 检索条件")
private String locationId; private String locationId;
/** 库存ID */
private String inventoryId;
/** 计划数量 */ /** 计划数量 */
@Excel(name = "计划数量") @Excel(name = "计划数量")
private Long plannedQuantity; private Long plannedQuantity;
...@@ -89,7 +93,15 @@ public class OutboundOrderItems extends BaseEntity ...@@ -89,7 +93,15 @@ public class OutboundOrderItems extends BaseEntity
@Excel(name = "排序号") @Excel(name = "排序号")
private String updateUserCode; private String updateUserCode;
public void setId(String id) public String getInventoryId() {
return inventoryId;
}
public void setInventoryId(String inventoryId) {
this.inventoryId = inventoryId;
}
public void setId(String id)
{ {
this.id = id; this.id = id;
} }
...@@ -292,6 +304,7 @@ public class OutboundOrderItems extends BaseEntity ...@@ -292,6 +304,7 @@ public class OutboundOrderItems extends BaseEntity
.append("createTime", getCreateTime()) .append("createTime", getCreateTime())
.append("createUserCode", getCreateUserCode()) .append("createUserCode", getCreateUserCode())
.append("updateTime", getUpdateTime()) .append("updateTime", getUpdateTime())
.append("inventoryId", getInventoryId())
.append("updateUserCode", getUpdateUserCode()) .append("updateUserCode", getUpdateUserCode())
.toString(); .toString();
} }
......
...@@ -22,6 +22,9 @@ public class OutboundOrderLog extends BaseEntity ...@@ -22,6 +22,9 @@ public class OutboundOrderLog extends BaseEntity
@Excel(name = "出货单号ID") @Excel(name = "出货单号ID")
private String orderId; private String orderId;
/** 库存ID */
private String inventoryId;
/** 货物ID */ /** 货物ID */
@Excel(name = "货物ID") @Excel(name = "货物ID")
private String materialId; private String materialId;
...@@ -81,7 +84,15 @@ public class OutboundOrderLog extends BaseEntity ...@@ -81,7 +84,15 @@ public class OutboundOrderLog extends BaseEntity
this.warehouseId = warehouseId; this.warehouseId = warehouseId;
} }
public String getWarehouseId() public String getInventoryId() {
return inventoryId;
}
public void setInventoryId(String inventoryId) {
this.inventoryId = inventoryId;
}
public String getWarehouseId()
{ {
return warehouseId; return warehouseId;
} }
...@@ -137,6 +148,7 @@ public class OutboundOrderLog extends BaseEntity ...@@ -137,6 +148,7 @@ public class OutboundOrderLog extends BaseEntity
.append("materialId", getMaterialId()) .append("materialId", getMaterialId())
.append("warehouseId", getWarehouseId()) .append("warehouseId", getWarehouseId())
.append("batchCode", getBatchCode()) .append("batchCode", getBatchCode())
.append("inventoryId", getInventoryId())
.append("actualQuantity", getActualQuantity()) .append("actualQuantity", getActualQuantity())
.append("itemStatus", getItemStatus()) .append("itemStatus", getItemStatus())
.append("isUsed", getIsUsed()) .append("isUsed", getIsUsed())
......
...@@ -53,6 +53,8 @@ public interface InventoryMapper ...@@ -53,6 +53,8 @@ public interface InventoryMapper
*/ */
public int updateInventory(Inventory inventory); public int updateInventory(Inventory inventory);
/** /**
* 删除库存 * 删除库存
* *
...@@ -69,7 +71,7 @@ public interface InventoryMapper ...@@ -69,7 +71,7 @@ public interface InventoryMapper
*/ */
public int deleteInventoryByIds(String[] ids); public int deleteInventoryByIds(String[] ids);
public List<Inventory> listByMatreialId(String materialId); public List<Inventory> listByMaterialId(String materialId);
/** /**
* @description: 获取库存盘点详细信息 * @description: 获取库存盘点详细信息
......
package com.ruoyi.inventory.mapper; package com.ruoyi.inventory.mapper;
import java.util.List; import java.util.List;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderLog; import com.ruoyi.inventory.domain.OutboundOrderLog;
/** /**
...@@ -19,6 +21,7 @@ public interface OutboundOrderLogMapper ...@@ -19,6 +21,7 @@ public interface OutboundOrderLogMapper
*/ */
public OutboundOrderLog selectOutboundOrderLogById(String id); public OutboundOrderLog selectOutboundOrderLogById(String id);
/** /**
* 查询出库明细子(仅用于锁定数量统计)列表 * 查询出库明细子(仅用于锁定数量统计)列表
* *
...@@ -34,7 +37,8 @@ public interface OutboundOrderLogMapper ...@@ -34,7 +37,8 @@ public interface OutboundOrderLogMapper
* @param outboundOrderLog 出库明细子(仅用于锁定数量统计) * @param outboundOrderLog 出库明细子(仅用于锁定数量统计)
* @return 出库明细子(仅用于锁定数量统计)集合 * @return 出库明细子(仅用于锁定数量统计)集合
*/ */
public Long selectLockedQuantity(OutboundOrderLog outboundOrderLog); public Long selectLockedQuantityByInventory(String id);
/** /**
* 新增出库明细子(仅用于锁定数量统计) * 新增出库明细子(仅用于锁定数量统计)
...@@ -66,6 +70,24 @@ public interface OutboundOrderLogMapper ...@@ -66,6 +70,24 @@ public interface OutboundOrderLogMapper
* @param ids 需要删除的数据主键集合 * @param ids 需要删除的数据主键集合
* @return 结果 * @return 结果
*/ */
public int deleteOutboundOrderLogByOrdersId(String id);
/**
* 批量删除出库明细子(仅用于锁定数量统计)
*
* @param ids 需要删除的数据主键集合
* @return 结果
*/
public int deleteOutboundOrderLogByIds(String[] ids); public int deleteOutboundOrderLogByIds(String[] ids);
/**
* 批量新增出库单明细
*
* @param outboundOrderItemsList 出库单明细列表
* @return 结果
*/
public int batchOutboundOrderLog(List<OutboundOrderLog> outboundOrderLogs);
} }
...@@ -2,21 +2,23 @@ package com.ruoyi.inventory.service; ...@@ -2,21 +2,23 @@ package com.ruoyi.inventory.service;
import java.util.List; import java.util.List;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.inventory.domain.Inventory; import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.StocktakeItems; import com.ruoyi.inventory.domain.StocktakeItems;
/** /**
* 库存Service接口 * 库存Service接口
* *
* @author ruoyi * @author ruoyi
* @date 2025-12-03 * @date 2025-12-03
*/ */
public interface IInventoryService public interface IInventoryService
{ {
/** /**
* 查询库存 * 查询库存
* *
* @param id 库存主键 * @param id 库存主键
* @return 库存 * @return 库存
*/ */
...@@ -24,7 +26,7 @@ public interface IInventoryService ...@@ -24,7 +26,7 @@ public interface IInventoryService
/** /**
* 查询库存列表 * 查询库存列表
* *
* @param inventory 库存 * @param inventory 库存
* @return 库存集合 * @return 库存集合
*/ */
...@@ -34,7 +36,7 @@ public interface IInventoryService ...@@ -34,7 +36,7 @@ public interface IInventoryService
/** /**
* 新增库存 * 新增库存
* *
* @param inventory 库存 * @param inventory 库存
* @return 结果 * @return 结果
*/ */
...@@ -49,15 +51,23 @@ public interface IInventoryService ...@@ -49,15 +51,23 @@ public interface IInventoryService
public int insertInventoryList(List<Inventory> inventoryList); public int insertInventoryList(List<Inventory> inventoryList);
/** /**
* 修改库存 * 修改库存
* *
* @param inventory 库存 * @param inventory 库存
* @return 结果 * @return 结果
*/ */
public int updateInventory(Inventory inventory); public int updateInventory(Inventory inventory);
int RefreshInventory(List<String> inventoryIds);
@SerialExecution(group = "inventoryRefresh", fair = true)
int ship(List<OutboundOrderItems> outboundOrderItems);
@SerialExecution(group = "inventoryRefresh", fair = true)
boolean inventoryLockValidation(List<OutboundOrderItems> outboundOrderItems);
/** /**
* 批量删除库存 * 批量删除库存
* *
* @param ids 需要删除的库存主键集合 * @param ids 需要删除的库存主键集合
* @return 结果 * @return 结果
*/ */
...@@ -65,14 +75,13 @@ public interface IInventoryService ...@@ -65,14 +75,13 @@ public interface IInventoryService
/** /**
* 删除库存信息 * 删除库存信息
* *
* @param id 库存主键 * @param id 库存主键
* @return 结果 * @return 结果
*/ */
public int deleteInventoryById(String id); public int deleteInventoryById(String id);
public List<Inventory> listByMatreialId(String materialId); public List<Inventory> listByMatreialId(String materialId);
/** /**
* @description: 获取库存盘点详细信息 * @description: 获取库存盘点详细信息
* @author cs * @author cs
...@@ -80,4 +89,6 @@ public interface IInventoryService ...@@ -80,4 +89,6 @@ public interface IInventoryService
* @version 1.0 * @version 1.0
*/ */
public List<StocktakeItems> selectstocktakeItemsList(); public List<StocktakeItems> selectstocktakeItemsList();
} }
...@@ -35,7 +35,6 @@ public interface IOutboundOrderLogService ...@@ -35,7 +35,6 @@ public interface IOutboundOrderLogService
*/ */
public int insertOutboundOrderLog(OutboundOrderLog outboundOrderLog); public int insertOutboundOrderLog(OutboundOrderLog outboundOrderLog);
Long selectLockedQuantity(OutboundOrderLog outboundOrderLog);
/** /**
* 修改出库明细子(仅用于锁定数量统计) * 修改出库明细子(仅用于锁定数量统计)
......
...@@ -58,4 +58,13 @@ public interface IOutboundOrdersService ...@@ -58,4 +58,13 @@ public interface IOutboundOrdersService
* @return 结果 * @return 结果
*/ */
public int deleteOutboundOrdersById(String id); public int deleteOutboundOrdersById(String id);
/**
* 出货
*
* @param id 出库单主主键
* @return 结果
*/
public int ship(OutboundOrders outboundOrders);
} }
package com.ruoyi.inventory.service.impl; package com.ruoyi.inventory.service.impl;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.inventory.domain.OutboundOrderItems;
import com.ruoyi.inventory.domain.OutboundOrderLog; import com.ruoyi.inventory.domain.OutboundOrderLog;
import com.ruoyi.inventory.domain.StocktakeItems; import com.ruoyi.inventory.domain.StocktakeItems;
import com.ruoyi.inventory.mapper.OutboundOrderLogMapper; import com.ruoyi.inventory.mapper.OutboundOrderLogMapper;
import org.springframework.beans.BeanUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.inventory.mapper.InventoryMapper; import com.ruoyi.inventory.mapper.InventoryMapper;
...@@ -16,7 +21,7 @@ import com.ruoyi.inventory.service.IInventoryService; ...@@ -16,7 +21,7 @@ import com.ruoyi.inventory.service.IInventoryService;
/** /**
* 库存Service业务层处理 * 库存Service业务层处理
* *
* @author ruoyi * @author ruoyi
* @date 2025-12-03 * @date 2025-12-03
*/ */
...@@ -30,7 +35,7 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -30,7 +35,7 @@ public class InventoryServiceImpl implements IInventoryService
/** /**
* 查询库存 * 查询库存
* *
* @param id 库存主键 * @param id 库存主键
* @return 库存 * @return 库存
*/ */
...@@ -42,7 +47,7 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -42,7 +47,7 @@ public class InventoryServiceImpl implements IInventoryService
/** /**
* 查询库存列表 * 查询库存列表
* *
* @param inventory 库存 * @param inventory 库存
* @return 库存 * @return 库存
*/ */
...@@ -52,19 +57,16 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -52,19 +57,16 @@ public class InventoryServiceImpl implements IInventoryService
return inventoryMapper.selectInventoryList(inventory); return inventoryMapper.selectInventoryList(inventory);
} }
@Override @Override
public Inventory selectInventory(Inventory inventory) public Inventory selectInventory(Inventory inventory)
{ {
Inventory inventory1 = inventoryMapper.selectInventory(inventory); return inventoryMapper.selectInventory(inventory);
OutboundOrderLog outboundOrderLog = new OutboundOrderLog();
BeanUtils.copyProperties(inventory1,outboundOrderLog);
inventory1.setLockedQuantity(outboundOrderLogMapper.selectLockedQuantity(outboundOrderLog));
return inventory1;
} }
/** /**
* 新增库存 * 新增库存
* *
* @param inventory 库存 * @param inventory 库存
* @return 结果 * @return 结果
*/ */
...@@ -72,6 +74,7 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -72,6 +74,7 @@ public class InventoryServiceImpl implements IInventoryService
public int insertInventory(Inventory inventory) public int insertInventory(Inventory inventory)
{ {
inventory.setCreateTime(DateUtils.getNowDate()); inventory.setCreateTime(DateUtils.getNowDate());
inventory.setCreateBy(SystemUtils.getUserName());
return inventoryMapper.insertInventory(inventory); return inventoryMapper.insertInventory(inventory);
} }
...@@ -85,25 +88,80 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -85,25 +88,80 @@ public class InventoryServiceImpl implements IInventoryService
} }
return count; return count;
} }
/** /**
* 修改库存 * 修改库存
* *
* @param inventory 库存 * @param inventory 库存
* @return 结果 * @return 结果
*/ */
@Override @Override
public int updateInventory(Inventory inventory) public int updateInventory(Inventory inventory)
{ {
List<Inventory> inventoryList = Collections.singletonList(inventory);
inventory.setUpdateTime(DateUtils.getNowDate()); inventory.setUpdateTime(DateUtils.getNowDate());
inventory.setUpdateBy(SystemUtils.getUserName());
return inventoryMapper.updateInventory(inventory); return inventoryMapper.updateInventory(inventory);
} }
@SerialExecution( group = "inventoryRefresh", fair = true)
@Override
public int RefreshInventory(List<String> inventoryIds)
{
for (String inventoryId : inventoryIds) {
// 1. 空值前置校验:跳过空的循环项
if (inventoryId == null) {
continue;
}
// 6. 查询锁定数量(优化:只查一次)
Long lockedQuantity = outboundOrderLogMapper.selectLockedQuantityByInventory(inventoryId);
Inventory inventory = new Inventory();
inventory.setLockedQuantity(lockedQuantity);
inventory.setId(inventoryId);
inventoryMapper.updateInventory(inventory);
}
return 1;
}
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override
public int ship(List<OutboundOrderItems> outboundOrderItems)
{
if (!outboundOrderItems.isEmpty()) {
for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {
OutboundOrderLog outboundOrderLog = outboundOrderLogMapper.selectOutboundOrderLogById(outboundOrderItem.getId());
Inventory inventory =inventoryMapper.selectInventoryById(outboundOrderLog.getInventoryId());
inventory.setQuantity(inventory.getQuantity()-outboundOrderItem.getActualQuantity());
inventory.setLockedQuantity(inventory.getQuantity()-outboundOrderItem.getActualQuantity());
if (inventory.getQuantity()==0){
inventory.setInventoryStatus(0l);
}
updateInventory(inventory);
}
}
return 1;
}
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override
public boolean inventoryLockValidation(List<OutboundOrderItems> outboundOrderItems)
{
if (!outboundOrderItems.isEmpty()) {
for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {
Inventory inventory = inventoryMapper.selectInventoryById(outboundOrderItem.getInventoryId());
if (inventory.getLockedQuantity()+outboundOrderItem.getActualQuantity()>inventory.getQuantity()){
return false;
}
}
return true;
}
return true;
}
/** /**
* 批量删除库存 * 批量删除库存
* *
* @param ids 需要删除的库存主键 * @param ids 需要删除的库存主键
* @return 结果 * @return 结果
*/ */
...@@ -115,7 +173,7 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -115,7 +173,7 @@ public class InventoryServiceImpl implements IInventoryService
/** /**
* 删除库存信息 * 删除库存信息
* *
* @param id 库存主键 * @param id 库存主键
* @return 结果 * @return 结果
*/ */
...@@ -125,11 +183,19 @@ public class InventoryServiceImpl implements IInventoryService ...@@ -125,11 +183,19 @@ public class InventoryServiceImpl implements IInventoryService
return inventoryMapper.deleteInventoryById(id); return inventoryMapper.deleteInventoryById(id);
} }
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override @Override
public List<Inventory> listByMatreialId(String materialId) { public List<Inventory> listByMatreialId(String materialId) {
return inventoryMapper.listByMatreialId(materialId); Inventory inventory = new Inventory();
inventory.setMaterialId(materialId);
List<String> inventoryIds = CollectionUtils.isEmpty(inventoryMapper.listByMaterialId(materialId))
? Collections.emptyList() // 空时返回空列表,避免后续NPE
: inventoryMapper.listByMaterialId(materialId).stream()
.map(inventory2 -> inventory2.getId()) // 提取ID(核心修正)
.collect(Collectors.toList());
RefreshInventory(inventoryIds);
return inventoryMapper.listByMaterialId(materialId);
} }
/** /**
* @description: 获取库存盘点详细信息 * @description: 获取库存盘点详细信息
* @author cs * @author cs
......
package com.ruoyi.inventory.service.impl; package com.ruoyi.inventory.service.impl;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderLog;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.ruoyi.inventory.mapper.OutboundOrderItemsMapper; import com.ruoyi.inventory.mapper.OutboundOrderItemsMapper;
...@@ -53,12 +49,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService ...@@ -53,12 +49,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
return outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems); return outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems);
} }
/**
* 新增出库单明细
*
* @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果
*/
@Override @Override
public int insertOutboundOrderItems(OutboundOrderItems outboundOrderItems) public int insertOutboundOrderItems(OutboundOrderItems outboundOrderItems)
{ {
...@@ -66,12 +57,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService ...@@ -66,12 +57,7 @@ public class OutboundOrderItemsServiceImpl implements IOutboundOrderItemsService
return outboundOrderItemsMapper.insertOutboundOrderItems(outboundOrderItems); return outboundOrderItemsMapper.insertOutboundOrderItems(outboundOrderItems);
} }
/**
* 修改出库单明细
*
* @param outboundOrderItemsInventory 出库单明细库存DTO
* @return 结果
*/
@Override @Override
public int updateOutboundOrderItems(OutboundOrderItems outboundOrderItems) public int updateOutboundOrderItems(OutboundOrderItems outboundOrderItems)
{ {
......
...@@ -54,10 +54,6 @@ public class OutboundOrderLogServiceImpl implements IOutboundOrderLogService ...@@ -54,10 +54,6 @@ public class OutboundOrderLogServiceImpl implements IOutboundOrderLogService
{ {
return outboundOrderLogMapper.insertOutboundOrderLog(outboundOrderLog); return outboundOrderLogMapper.insertOutboundOrderLog(outboundOrderLog);
} }
@Override
public Long selectLockedQuantity(OutboundOrderLog outboundOrderLog){
return outboundOrderLogMapper.selectLockedQuantity(outboundOrderLog);
}
/** /**
* 修改出库明细子(仅用于锁定数量统计) * 修改出库明细子(仅用于锁定数量统计)
* *
......
package com.ruoyi.inventory.service.impl; package com.ruoyi.inventory.service.impl;
import java.util.List; import java.util.List;
import com.ruoyi.common.annotation.SerialExecution;
import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.inventory.domain.Inventory;
import com.ruoyi.inventory.domain.OutboundOrderLog;
import com.ruoyi.inventory.mapper.InventoryMapper;
import com.ruoyi.inventory.mapper.OutboundOrderItemsMapper;
import com.ruoyi.inventory.mapper.OutboundOrderLogMapper;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.UUID;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.inventory.domain.OutboundOrderItems; import com.ruoyi.inventory.domain.OutboundOrderItems;
...@@ -14,19 +25,26 @@ import com.ruoyi.inventory.service.IOutboundOrdersService; ...@@ -14,19 +25,26 @@ import com.ruoyi.inventory.service.IOutboundOrdersService;
/** /**
* 出库单主Service业务层处理 * 出库单主Service业务层处理
* *
* @author ruoyi * @author ruoyi
* @date 2025-12-03 * @date 2025-12-03
*/ */
@Service @Service
public class OutboundOrdersServiceImpl implements IOutboundOrdersService public class OutboundOrdersServiceImpl implements IOutboundOrdersService
{ {
@Autowired @Autowired
private OutboundOrdersMapper outboundOrdersMapper; private OutboundOrdersMapper outboundOrdersMapper;
@Autowired
private OutboundOrderItemsMapper outboundOrderItemsMapper;
@Autowired
private OutboundOrderLogMapper outboundOrderLogMapper;
@Autowired
private InventoryServiceImpl inventoryService;
/** /**
* 查询出库单主 * 查询出库单主
* *
* @param id 出库单主主键 * @param id 出库单主主键
* @return 出库单主 * @return 出库单主
*/ */
...@@ -39,7 +57,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -39,7 +57,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/** /**
* 查询出库单主列表 * 查询出库单主列表
* *
* @param outboundOrders 出库单主 * @param outboundOrders 出库单主
* @return 出库单主 * @return 出库单主
*/ */
...@@ -51,7 +69,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -51,7 +69,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/** /**
* 新增出库单主 * 新增出库单主
* *
* @param outboundOrders 出库单主 * @param outboundOrders 出库单主
* @return 结果 * @return 结果
*/ */
...@@ -60,6 +78,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -60,6 +78,8 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
public int insertOutboundOrders(OutboundOrders outboundOrders) public int insertOutboundOrders(OutboundOrders outboundOrders)
{ {
outboundOrders.setCreateTime(DateUtils.getNowDate()); outboundOrders.setCreateTime(DateUtils.getNowDate());
outboundOrders.setCreateBy(SystemUtils.getUserName());
outboundOrders.setId(UUID.randomUUID().toString());
int rows = outboundOrdersMapper.insertOutboundOrders(outboundOrders); int rows = outboundOrdersMapper.insertOutboundOrders(outboundOrders);
insertOutboundOrderItems(outboundOrders); insertOutboundOrderItems(outboundOrders);
return rows; return rows;
...@@ -67,7 +87,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -67,7 +87,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/** /**
* 修改出库单主 * 修改出库单主
* *
* @param outboundOrders 出库单主 * @param outboundOrders 出库单主
* @return 结果 * @return 结果
*/ */
...@@ -77,13 +97,14 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -77,13 +97,14 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
{ {
outboundOrders.setUpdateTime(DateUtils.getNowDate()); outboundOrders.setUpdateTime(DateUtils.getNowDate());
outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(outboundOrders.getId()); outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(outboundOrders.getId());
outboundOrderLogMapper.deleteOutboundOrderLogByOrdersId(outboundOrders.getId());
insertOutboundOrderItems(outboundOrders); insertOutboundOrderItems(outboundOrders);
return outboundOrdersMapper.updateOutboundOrders(outboundOrders); return outboundOrdersMapper.updateOutboundOrders(outboundOrders);
} }
/** /**
* 批量删除出库单主 * 批量删除出库单主
* *
* @param ids 需要删除的出库单主主键 * @param ids 需要删除的出库单主主键
* @return 结果 * @return 结果
*/ */
...@@ -97,7 +118,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -97,7 +118,7 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
/** /**
* 删除出库单主信息 * 删除出库单主信息
* *
* @param id 出库单主主键 * @param id 出库单主主键
* @return 结果 * @return 结果
*/ */
...@@ -108,26 +129,88 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService ...@@ -108,26 +129,88 @@ public class OutboundOrdersServiceImpl implements IOutboundOrdersService
outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(id); outboundOrdersMapper.deleteOutboundOrderItemsByOrderId(id);
return outboundOrdersMapper.deleteOutboundOrdersById(id); return outboundOrdersMapper.deleteOutboundOrdersById(id);
} }
@SerialExecution(group = "inventoryRefresh", fair = true)
@Override
public int ship(OutboundOrders outboundOrders) {
OutboundOrderItems outboundOrderItems1 = new OutboundOrderItems();
outboundOrderItems1.setOrderId(outboundOrders.getId());
List<OutboundOrderItems> outboundOrderItems = outboundOrderItemsMapper.selectOutboundOrderItemsList(outboundOrderItems1);
List<OutboundOrderItems> outboundOrderItems2 = outboundOrderItems;
OutboundOrderLog outboundOrderLog = new OutboundOrderLog();
for (OutboundOrderItems outboundOrderItem : outboundOrderItems) {
outboundOrderItem.setItemStatus(3l);
outboundOrderItemsMapper.updateOutboundOrderItems(outboundOrderItem);
outboundOrderLog.setId(outboundOrderItem.getId());
outboundOrderLog.setItemStatus(outboundOrderItem.getItemStatus());
outboundOrderLogMapper.updateOutboundOrderLog(outboundOrderLog);
}
outboundOrders.setId(outboundOrders.getId());
outboundOrders.setOrderStatus(3l);
outboundOrders.setUpdateTime(DateUtils.getNowDate());
outboundOrders.setUpdateBy(SystemUtils.getUserName());
outboundOrdersMapper.updateOutboundOrders(outboundOrders);
inventoryService.ship(outboundOrderItems2);
return 1;
}
/** /**
* 新增出库单明细信息 * 新增出库单明细信息
* *
* @param outboundOrders 出库单主对象 * @param outboundOrders 出库单主对象
*/ */
public void insertOutboundOrderItems(OutboundOrders outboundOrders) public void insertOutboundOrderItems(OutboundOrders outboundOrders) {
{
List<OutboundOrderItems> outboundOrderItemsList = outboundOrders.getOutboundOrderItemsList(); List<OutboundOrderItems> outboundOrderItemsList = outboundOrders.getOutboundOrderItemsList();
String id = outboundOrders.getId(); String id = outboundOrders.getId();
if (StringUtils.isNotNull(outboundOrderItemsList)) // 1. 先做空列表校验(提前返回,避免无效逻辑)
{ if (outboundOrderItemsList == null || outboundOrderItemsList.isEmpty()) {
for (OutboundOrderItems outboundOrderItems : outboundOrderItemsList) return;
{ }
outboundOrderItems.setOrderId(id);
} // 2. 库存校验:失败时抛异常(核心修正:! 取反 + 异常抛出后代码立即终止)
if (outboundOrderItemsList.size() > 0) boolean isValid = inventoryService.inventoryLockValidation(outboundOrderItemsList);
{ if (!isValid) { // 校验失败(返回false)时抛异常
outboundOrdersMapper.batchOutboundOrderItems(outboundOrderItemsList); throw new RuntimeException("库存被修改请重新确认"); // 抛异常后,方法立即停止运行
} }
// 2. 为明细设置订单ID和主键ID
for (OutboundOrderItems items : outboundOrderItemsList) {
items.setOrderId(id);
// 生成无横线的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); // 单个对象属性拷贝
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);
} }
} }
} }
...@@ -123,9 +123,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -123,9 +123,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<include refid="selectInventoryVo"/> <include refid="selectInventoryVo"/>
where id = #{id} where id = #{id}
</select> </select>
<select id="listByMatreialId" parameterType="String" resultMap="InventoryResult"> <select id="listByMaterialId" parameterType="String" resultMap="InventoryResult">
<include refid="selectInventoryVo"/> <include refid="selectInventoryVo"/>
where material_id = #{materialId} where 1=1
<if test="materialId != null and materialId.trim() != ''">
and material_id = #{materialId}
</if>
<![CDATA[
and inventory_status = '1'
and quantity > locked_quantity
]]>
</select> </select>
<insert id="insertInventory" parameterType="Inventory"> <insert id="insertInventory" parameterType="Inventory">
insert into inventory insert into inventory
......
...@@ -11,6 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -11,6 +11,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="batchCode" column="batch_code" /> <result property="batchCode" column="batch_code" />
<result property="warehouseId" column="warehouse_id" /> <result property="warehouseId" column="warehouse_id" />
<result property="locationId" column="location_id" /> <result property="locationId" column="location_id" />
<result property="inventoryId" column="inventory_id" />
<result property="plannedQuantity" column="planned_quantity" /> <result property="plannedQuantity" column="planned_quantity" />
<result property="actualQuantity" column="actual_quantity" /> <result property="actualQuantity" column="actual_quantity" />
<result property="divisor" column="divisor" /> <result property="divisor" column="divisor" />
...@@ -29,7 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -29,7 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap> </resultMap>
<sql id="selectOutboundOrderItemsVo"> <sql id="selectOutboundOrderItemsVo">
select id, order_id, material_id, batch_code, warehouse_id, location_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_order_items select id, order_id, material_id, batch_code, warehouse_id, location_id, inventory_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_order_items
</sql> </sql>
<select id="selectOutboundOrderItemsList" parameterType="OutboundOrderItems" resultMap="OutboundOrderItemsResult"> <select id="selectOutboundOrderItemsList" parameterType="OutboundOrderItems" resultMap="OutboundOrderItemsResult">
...@@ -40,6 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -40,6 +41,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if> <if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if> <if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
<if test="locationId != null and locationId != ''"> and location_id = #{locationId}</if> <if test="locationId != null and locationId != ''"> and location_id = #{locationId}</if>
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
<if test="plannedQuantity != null "> and planned_quantity = #{plannedQuantity}</if> <if test="plannedQuantity != null "> and planned_quantity = #{plannedQuantity}</if>
<if test="actualQuantity != null "> and actual_quantity = #{actualQuantity}</if> <if test="actualQuantity != null "> and actual_quantity = #{actualQuantity}</if>
<if test="divisor != null "> and divisor = #{divisor}</if> <if test="divisor != null "> and divisor = #{divisor}</if>
...@@ -69,6 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -69,6 +71,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null">batch_code,</if> <if test="batchCode != null">batch_code,</if>
<if test="warehouseId != null">warehouse_id,</if> <if test="warehouseId != null">warehouse_id,</if>
<if test="locationId != null">location_id,</if> <if test="locationId != null">location_id,</if>
<if test="inventoryId != null">inventory_id,</if>
<if test="plannedQuantity != null">planned_quantity,</if> <if test="plannedQuantity != null">planned_quantity,</if>
<if test="actualQuantity != null">actual_quantity,</if> <if test="actualQuantity != null">actual_quantity,</if>
<if test="divisor != null">divisor,</if> <if test="divisor != null">divisor,</if>
...@@ -92,6 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -92,6 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null">#{batchCode},</if> <if test="batchCode != null">#{batchCode},</if>
<if test="warehouseId != null">#{warehouseId},</if> <if test="warehouseId != null">#{warehouseId},</if>
<if test="locationId != null">#{locationId},</if> <if test="locationId != null">#{locationId},</if>
<if test="inventoryId != null">#{inventoryId},</if>
<if test="plannedQuantity != null">#{plannedQuantity},</if> <if test="plannedQuantity != null">#{plannedQuantity},</if>
<if test="actualQuantity != null">#{actualQuantity},</if> <if test="actualQuantity != null">#{actualQuantity},</if>
<if test="divisor != null">#{divisor},</if> <if test="divisor != null">#{divisor},</if>
...@@ -118,6 +122,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -118,6 +122,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="batchCode != null">batch_code = #{batchCode},</if> <if test="batchCode != null">batch_code = #{batchCode},</if>
<if test="warehouseId != null">warehouse_id = #{warehouseId},</if> <if test="warehouseId != null">warehouse_id = #{warehouseId},</if>
<if test="locationId != null">location_id = #{locationId},</if> <if test="locationId != null">location_id = #{locationId},</if>
<if test="inventoryId != null">inventory_id = #{inventoryId},</if>
<if test="plannedQuantity != null">planned_quantity = #{plannedQuantity},</if> <if test="plannedQuantity != null">planned_quantity = #{plannedQuantity},</if>
<if test="actualQuantity != null">actual_quantity = #{actualQuantity},</if> <if test="actualQuantity != null">actual_quantity = #{actualQuantity},</if>
<if test="divisor != null">divisor = #{divisor},</if> <if test="divisor != null">divisor = #{divisor},</if>
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
<resultMap type="OutboundOrderLog" id="OutboundOrderLogResult"> <resultMap type="OutboundOrderLog" id="OutboundOrderLogResult">
<result property="id" column="id" /> <result property="id" column="id" />
<result property="orderId" column="order_id" /> <result property="orderId" column="order_id" />
<result property="inventoryId" column="inventory_id" />
<result property="materialId" column="material_id" /> <result property="materialId" column="material_id" />
<result property="warehouseId" column="warehouse_id" /> <result property="warehouseId" column="warehouse_id" />
<result property="batchCode" column="batch_code" /> <result property="batchCode" column="batch_code" />
...@@ -15,8 +16,9 @@ ...@@ -15,8 +16,9 @@
<result property="isUsed" column="is_used" /> <result property="isUsed" column="is_used" />
</resultMap> </resultMap>
<!-- 补充inventory_id到查询字段中 -->
<sql id="selectOutboundOrderLogVo"> <sql id="selectOutboundOrderLogVo">
select id, order_id, material_id, warehouse_id, batch_code, actual_quantity, item_status, is_used select id, order_id, inventory_id, material_id, warehouse_id, batch_code, actual_quantity, item_status, is_used
from outbound_order_log from outbound_order_log
</sql> </sql>
...@@ -24,6 +26,7 @@ ...@@ -24,6 +26,7 @@
<include refid="selectOutboundOrderLogVo"/> <include refid="selectOutboundOrderLogVo"/>
<where> <where>
<if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if> <if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if>
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
<if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if> <if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if>
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if> <if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if> <if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
...@@ -33,26 +36,39 @@ ...@@ -33,26 +36,39 @@
</where> </where>
</select> </select>
<select id="selectLockedQuantity" parameterType="OutboundOrderLog" resultType="java.lang.Long"> <select id="deleteLog" parameterType="OutboundOrderLog" resultMap="OutboundOrderLogResult">
select ifnull(sum(actual_quantity), 0) delete from outbound_order_log
from outbound_order_log
<where> <where>
<if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if> <if test="materialId != null and materialId != ''"> and material_id = #{materialId}</if>
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if> <if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
<if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if> <if test="batchCode != null and batchCode != ''"> and batch_code = #{batchCode}</if>
<if test="itemStatus != null "> and item_status = #{itemStatus}</if>
<!-- 补充inventory_id条件 -->
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
</where> </where>
</select> </select>
<!-- 修正参数错误:原#{id}改为#{inventoryId} -->
<select id="selectLockedQuantityByInventory" parameterType="OutboundOrderLog" resultType="java.lang.Long">
select ifnull(sum(actual_quantity), 0)
from outbound_order_log
where item_status=1
<if test="inventoryId != null and inventoryId != ''"> and inventory_id = #{inventoryId}</if>
</select>
<select id="selectOutboundOrderLogById" parameterType="String" resultMap="OutboundOrderLogResult"> <select id="selectOutboundOrderLogById" parameterType="String" resultMap="OutboundOrderLogResult">
<include refid="selectOutboundOrderLogVo"/> <include refid="selectOutboundOrderLogVo"/>
where id = #{id} where id = #{id}
</select> </select>
<!-- 插入语句补充inventory_id -->
<insert id="insertOutboundOrderLog" parameterType="OutboundOrderLog"> <insert id="insertOutboundOrderLog" parameterType="OutboundOrderLog">
insert into outbound_order_log insert into outbound_order_log
<trim prefix="(" suffix=")" suffixOverrides=","> <trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">id,</if> <if test="id != null">id,</if>
<if test="orderId != null">order_id,</if> <if test="orderId != null">order_id,</if>
<if test="inventoryId != null">inventory_id,</if>
<if test="materialId != null">material_id,</if> <if test="materialId != null">material_id,</if>
<if test="warehouseId != null">warehouse_id,</if> <if test="warehouseId != null">warehouse_id,</if>
<if test="batchCode != null">batch_code,</if> <if test="batchCode != null">batch_code,</if>
...@@ -63,6 +79,7 @@ ...@@ -63,6 +79,7 @@
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if> <if test="id != null">#{id},</if>
<if test="orderId != null">#{orderId},</if> <if test="orderId != null">#{orderId},</if>
<if test="inventoryId != null">#{inventoryId},</if>
<if test="materialId != null">#{materialId},</if> <if test="materialId != null">#{materialId},</if>
<if test="warehouseId != null">#{warehouseId},</if> <if test="warehouseId != null">#{warehouseId},</if>
<if test="batchCode != null">#{batchCode},</if> <if test="batchCode != null">#{batchCode},</if>
...@@ -72,10 +89,12 @@ ...@@ -72,10 +89,12 @@
</trim> </trim>
</insert> </insert>
<!-- 更新语句补充inventory_id -->
<update id="updateOutboundOrderLog" parameterType="OutboundOrderLog"> <update id="updateOutboundOrderLog" parameterType="OutboundOrderLog">
update outbound_order_log update outbound_order_log
<trim prefix="SET" suffixOverrides=","> <trim prefix="SET" suffixOverrides=",">
<if test="orderId != null">order_id = #{orderId},</if> <if test="orderId != null">order_id = #{orderId},</if>
<if test="inventoryId != null">inventory_id = #{inventoryId},</if>
<if test="materialId != null">material_id = #{materialId},</if> <if test="materialId != null">material_id = #{materialId},</if>
<if test="warehouseId != null">warehouse_id = #{warehouseId},</if> <if test="warehouseId != null">warehouse_id = #{warehouseId},</if>
<if test="batchCode != null">batch_code = #{batchCode},</if> <if test="batchCode != null">batch_code = #{batchCode},</if>
...@@ -90,10 +109,39 @@ ...@@ -90,10 +109,39 @@
delete from outbound_order_log where id = #{id} delete from outbound_order_log where id = #{id}
</delete> </delete>
<delete id="deleteOutboundOrderLogByIds" parameterType="String"> <delete id="deleteOutboundOrderLogByOrdersId" parameterType="String">
delete from outbound_order_log where id in delete from outbound_order_log where order_id = #{id}
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete> </delete>
<!-- 批量插入补充inventory_id -->
<insert id="batchOutboundOrderLog">
<!-- 增加非空判断,避免空列表导致SQL语法错误 -->
<if test="list != null and list.size() > 0">
insert into outbound_order_log(
id,
order_id,
inventory_id, <!-- 新增 -->
material_id,
warehouse_id,
batch_code, <!-- 对应实体类batchCode -->
actual_quantity,
item_status,
is_used
) values
<foreach item="item" index="index" collection="list" separator=",">
(
#{item.id},
#{item.orderId},
#{item.inventoryId},
#{item.materialId},
#{item.warehouseId},
#{item.batchCode},
#{item.actualQuantity},
#{item.itemStatus},
#{item.isUsed}
)
</foreach>
</if>
</insert>
</mapper> </mapper>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper <!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd"> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.inventory.mapper.OutboundOrdersMapper"> <mapper namespace="com.ruoyi.inventory.mapper.OutboundOrdersMapper">
<resultMap type="OutboundOrders" id="OutboundOrdersResult"> <resultMap type="OutboundOrders" id="OutboundOrdersResult">
<result property="id" column="id" /> <result property="id" column="id" />
<result property="orderId" column="order_id" /> <result property="orderId" column="order_id" />
...@@ -31,40 +31,40 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -31,40 +31,40 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<collection property="outboundOrderItemsList" ofType="OutboundOrderItems" column="id" select="selectOutboundOrderItemsList" /> <collection property="outboundOrderItemsList" ofType="OutboundOrderItems" column="id" select="selectOutboundOrderItemsList" />
</resultMap> </resultMap>
<!-- 修复:仅保留子表outbound_order_items的字段映射,删除错误的主表字段 -->
<resultMap type="OutboundOrderItems" id="OutboundOrderItemsResult"> <resultMap type="OutboundOrderItems" id="OutboundOrderItemsResult">
<result property="id" column="id" /> <result property="id" column="id" />
<result property="orderId" column="order_id" /> <result property="orderId" column="order_id" />
<result property="materialId" column="material_id" /> <result property="materialId" column="material_id" />
<result property="batchId" column="batch_id" /> <result property="batchCode" column="batch_code" />
<result property="warehouseId" column="warehouse_id" /> <result property="warehouseId" column="warehouse_id" />
<result property="locationId" column="location_id" /> <result property="locationId" column="location_id" />
<result property="plannedQuantity" column="planned_quantity" /> <result property="plannedQuantity" column="planned_quantity" />
<result property="actualQuantity" column="actual_quantity" /> <result property="inventoryId" column="inventory_id" />
<result property="plannedPackages" column="planned_packages" /> <result property="actualQuantity" column="actual_quantity" />
<result property="actualPackages" column="actual_packages" /> <result property="divisor" column="divisor" />
<result property="divisor" column="divisor" /> <result property="labelColor" column="label_color" />
<result property="labelColor" column="label_color" /> <result property="voucherNumber" column="voucher_number" />
<result property="voucherNumber" column="voucher_number" /> <result property="itemStatus" column="item_status" />
<result property="unitPrice" column="unit_price" /> <result property="shippedAt" column="shipped_at" />
<result property="itemStatus" column="item_status" /> <result property="shippedBy" column="shipped_by" />
<result property="receivedAt" column="received_at" /> <result property="remark" column="remark" />
<result property="receivedBy" column="received_by" /> <result property="isUsed" column="is_used" />
<result property="remark" column="remark" /> <result property="sortNo" column="sort_no" />
<result property="isUsed" column="is_used" /> <result property="createTime" column="create_time" />
<result property="sortNo" column="sort_no" /> <result property="createUserCode" column="create_user_code" />
<result property="createTime" column="create_time" /> <result property="updateTime" column="update_time" />
<result property="createUserCode" column="create_user_code" /> <result property="updateUserCode" column="update_user_code" />
<result property="updateTime" column="update_time" />
<result property="updateUserCode" column="update_user_code" />
</resultMap> </resultMap>
<sql id="selectOutboundOrdersVo"> <sql id="selectOutboundOrdersVo">
select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_orders select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code from outbound_orders
</sql> </sql>
<select id="selectOutboundOrdersList" parameterType="OutboundOrders" resultMap="OutboundOrdersResult"> <select id="selectOutboundOrdersList" parameterType="OutboundOrders" resultMap="OutboundOrdersResult">
<include refid="selectOutboundOrdersVo"/> <include refid="selectOutboundOrdersVo"/>
<where> <where>
<if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if> <if test="orderId != null and orderId != ''"> and order_id = #{orderId}</if>
<if test="systemNo != null and systemNo != ''"> and system_no = #{systemNo}</if> <if test="systemNo != null and systemNo != ''"> and system_no = #{systemNo}</if>
<if test="orderTypeId != null and orderTypeId != ''"> and order_type_id = #{orderTypeId}</if> <if test="orderTypeId != null and orderTypeId != ''"> and order_type_id = #{orderTypeId}</if>
...@@ -83,16 +83,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -83,16 +83,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="updateUserCode != null and updateUserCode != ''"> and update_user_code = #{updateUserCode}</if> <if test="updateUserCode != null and updateUserCode != ''"> and update_user_code = #{updateUserCode}</if>
</where> </where>
</select> </select>
<select id="selectOutboundOrdersById" parameterType="String" resultMap="OutboundOrdersOutboundOrderItemsResult"> <select id="selectOutboundOrdersById" parameterType="String" resultMap="OutboundOrdersOutboundOrderItemsResult">
select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code select id, order_id, system_no, order_type_id, batch_code, warehouse_id, owner_id, order_status, inbound_date, destination, total_planned_quantity, total_actual_quantity, total_packages, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code
from outbound_orders from outbound_orders
where id = #{id} where id = #{id}
</select> </select>
<!-- 仅保留子表查询逻辑,字段完整且映射正确 -->
<select id="selectOutboundOrderItemsList" parameterType="String" resultMap="OutboundOrderItemsResult"> <select id="selectOutboundOrderItemsList" parameterType="String" resultMap="OutboundOrderItemsResult">
select id, order_id, material_id, batch_code, warehouse_id, location_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code select id, order_id, material_id, batch_code, warehouse_id, location_id, planned_quantity, actual_quantity, divisor, label_color, voucher_number, item_status, shipped_at, shipped_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code , inventory_id
from outbound_order_items from outbound_order_items
where order_id = #{id} where order_id = #{id}
</select> </select>
...@@ -119,7 +120,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -119,7 +120,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createUserCode != null">create_user_code,</if> <if test="createUserCode != null">create_user_code,</if>
<if test="updateTime != null">update_time,</if> <if test="updateTime != null">update_time,</if>
<if test="updateUserCode != null">update_user_code,</if> <if test="updateUserCode != null">update_user_code,</if>
</trim> </trim>
<trim prefix="values (" suffix=")" suffixOverrides=","> <trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">#{id},</if> <if test="id != null">#{id},</if>
<if test="orderId != null">#{orderId},</if> <if test="orderId != null">#{orderId},</if>
...@@ -141,7 +142,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -141,7 +142,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="createUserCode != null">#{createUserCode},</if> <if test="createUserCode != null">#{createUserCode},</if>
<if test="updateTime != null">#{updateTime},</if> <if test="updateTime != null">#{updateTime},</if>
<if test="updateUserCode != null">#{updateUserCode},</if> <if test="updateUserCode != null">#{updateUserCode},</if>
</trim> </trim>
</insert> </insert>
<update id="updateOutboundOrders" parameterType="OutboundOrders"> <update id="updateOutboundOrders" parameterType="OutboundOrders">
...@@ -175,14 +176,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -175,14 +176,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete> </delete>
<delete id="deleteOutboundOrdersByIds" parameterType="String"> <delete id="deleteOutboundOrdersByIds" parameterType="String">
delete from outbound_orders where id in delete from outbound_orders where id in
<foreach item="id" collection="array" open="(" separator="," close=")"> <foreach item="id" collection="array" open="(" separator="," close=")">
#{id} #{id}
</foreach> </foreach>
</delete> </delete>
<delete id="deleteOutboundOrderItemsByOrderIds" parameterType="String"> <delete id="deleteOutboundOrderItemsByOrderIds" parameterType="String">
delete from outbound_order_items where order_id in delete from outbound_order_items where order_id in
<foreach item="orderId" collection="array" open="(" separator="," close=")"> <foreach item="orderId" collection="array" open="(" separator="," close=")">
#{orderId} #{orderId}
</foreach> </foreach>
...@@ -193,9 +194,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" ...@@ -193,9 +194,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</delete> </delete>
<insert id="batchOutboundOrderItems"> <insert id="batchOutboundOrderItems">
insert into outbound_order_items( id, order_id, material_id, batch_id, warehouse_id, location_id, planned_quantity, actual_quantity, planned_packages, actual_packages, divisor, label_color, voucher_number, unit_price, item_status, received_at, received_by, remark, is_used, sort_no, create_time, create_user_code, update_time, update_user_code) values insert into outbound_order_items(
id, order_id, material_id, batch_code, warehouse_id, location_id,
planned_quantity, actual_quantity, divisor, label_color, voucher_number,
item_status, shipped_at, shipped_by, remark, is_used, sort_no,
create_time, create_user_code, update_time, update_user_code,inventory_id
) values
<foreach item="item" index="index" collection="list" separator=","> <foreach item="item" index="index" collection="list" separator=",">
( #{item.id}, #{item.orderId}, #{item.materialId}, #{item.batchId}, #{item.warehouseId}, #{item.locationId}, #{item.plannedQuantity}, #{item.actualQuantity}, #{item.plannedPackages}, #{item.actualPackages}, #{item.divisor}, #{item.labelColor}, #{item.voucherNumber}, #{item.unitPrice}, #{item.itemStatus}, #{item.receivedAt}, #{item.receivedBy}, #{item.remark}, #{item.isUsed}, #{item.sortNo}, #{item.createTime}, #{item.createUserCode}, #{item.updateTime}, #{item.updateUserCode}) (
#{item.id}, #{item.orderId}, #{item.materialId}, #{item.batchCode}, #{item.warehouseId},
#{item.locationId}, #{item.plannedQuantity}, #{item.actualQuantity}, #{item.divisor},
#{item.labelColor}, #{item.voucherNumber}, #{item.itemStatus}, #{item.shippedAt},
#{item.shippedBy}, #{item.remark}, #{item.isUsed}, #{item.sortNo}, #{item.createTime},
#{item.createUserCode}, #{item.updateTime}, #{item.updateUserCode},#{item.inventoryId}
)
</foreach> </foreach>
</insert> </insert>
</mapper> </mapper>
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论