feat: 完善盘点出入库流程
This commit is contained in:
28
pda/api/warehouse/inventory.js
Normal file
28
pda/api/warehouse/inventory.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 获取盘点待处理任务列表
|
||||||
|
export function getInventoryTaskList(query) {
|
||||||
|
return request({
|
||||||
|
url: '/pda/inventoryTaskList',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 扫码查询盘点任务详情
|
||||||
|
export function getInventoryDetail(query) {
|
||||||
|
return request({
|
||||||
|
url: '/pda/inventoryDetail',
|
||||||
|
method: 'get',
|
||||||
|
params: query
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 确认盘点
|
||||||
|
export function confirmInventory(data) {
|
||||||
|
return request({
|
||||||
|
url: '/pda/inventoryConfirm',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -1,61 +1,237 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="page-container">
|
<view class="page-container">
|
||||||
<view class="menu-section">
|
<view class="scan-section">
|
||||||
<view class="menu-card" @click="scanInventory">
|
<view class="scan-header">
|
||||||
<view class="card-left">
|
<view>
|
||||||
<view class="card-icon green">
|
<text class="scan-title">盘点扫码</text>
|
||||||
<uni-icons type="scan" size="24" color="#fff"></uni-icons>
|
<text class="scan-subtitle">WCS 出库到位后扫描托盘核对物料</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-info">
|
<view class="scan-btn" @click="startScan">
|
||||||
<text class="card-title">扫码盘点</text>
|
<uni-icons type="scan" size="18" color="#1f8f4d"></uni-icons>
|
||||||
<text class="card-desc">扫描托盘码进行库存盘点</text>
|
<text class="scan-btn-text">扫码</text>
|
||||||
</view>
|
|
||||||
</view>
|
</view>
|
||||||
<uni-icons type="right" size="18" color="#ccc"></uni-icons>
|
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view class="menu-card reserve-card" @click="showReservedTip">
|
<view class="input-row">
|
||||||
<view class="card-left">
|
<text class="input-label">任务号</text>
|
||||||
<view class="card-icon gray">
|
<input class="scan-input" v-model="taskNo" placeholder="选填" @confirm="handleSearch" />
|
||||||
<uni-icons type="compose" size="24" color="#fff"></uni-icons>
|
</view>
|
||||||
|
<view class="input-row">
|
||||||
|
<text class="input-label">托盘码</text>
|
||||||
|
<input class="scan-input" v-model="barcode" placeholder="请输入或扫描托盘码" @confirm="handleSearch" />
|
||||||
|
</view>
|
||||||
|
<button class="query-btn" @click="handleSearch">查询盘点任务</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="task-section">
|
||||||
|
<view class="section-header">
|
||||||
|
<text class="section-title">待盘点任务</text>
|
||||||
|
<text class="section-action" @click="loadTasks">刷新</text>
|
||||||
|
</view>
|
||||||
|
<view v-if="taskList.length === 0" class="empty-state">
|
||||||
|
<text class="empty-text">暂无待盘点任务</text>
|
||||||
|
</view>
|
||||||
|
<view v-else>
|
||||||
|
<view class="task-card" v-for="item in taskList" :key="item.jobId" @click="selectTask(item)">
|
||||||
|
<view class="task-header">
|
||||||
|
<text class="task-type">{{ item.typeName }}</text>
|
||||||
|
<text class="task-no">{{ item.taskNo }}</text>
|
||||||
</view>
|
</view>
|
||||||
<view class="card-info">
|
<view class="task-body">
|
||||||
<text class="card-title">预留界面</text>
|
<view class="task-line">
|
||||||
<text class="card-desc">后续盘点流程启用时接入</text>
|
<text class="line-label">托盘</text>
|
||||||
|
<text class="line-value">{{ item.trayCode || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="task-line">
|
||||||
|
<text class="line-label">物料</text>
|
||||||
|
<text class="line-value">{{ item.materialCode || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="task-line">
|
||||||
|
<text class="line-label">数量</text>
|
||||||
|
<text class="line-value highlight">{{ item.quantity || 0 }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="task-footer">
|
||||||
|
<text class="task-time">{{ item.createTime }}</text>
|
||||||
|
<text class="task-status" :class="item.statusClass">{{ item.statusName }}</text>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
<uni-icons type="right" size="18" color="#ddd"></uni-icons>
|
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<view v-if="scanCode" class="result-card">
|
<view class="form-section" v-if="inventoryInfo">
|
||||||
<view class="result-header">
|
<text class="form-title">盘点信息</text>
|
||||||
<text class="result-title">最近扫描</text>
|
<view class="info-row">
|
||||||
<text class="result-code">{{ scanCode }}</text>
|
<text class="info-label">任务号</text>
|
||||||
|
<text class="info-value">{{ inventoryInfo.taskNo }}</text>
|
||||||
</view>
|
</view>
|
||||||
<text class="result-desc">扫码盘点明细待业务流程确认后接入。</text>
|
<view class="info-row">
|
||||||
|
<text class="info-label">托盘号</text>
|
||||||
|
<text class="info-value">{{ inventoryInfo.trayCode }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">原货位</text>
|
||||||
|
<text class="info-value">{{ inventoryInfo.locationCode || '-' }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="info-row">
|
||||||
|
<text class="info-label">盘点总数</text>
|
||||||
|
<text class="info-value highlight">{{ calculateActualTotal() }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="phase-tip" :class="{ ready: inventoryInfo.executionPhase === '5' }">
|
||||||
|
{{ inventoryInfo.executionPhase === '5' ? '已到达出口,可确认盘点' : '等待 WCS 出库完成后再确认' }}
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="form-section" v-if="inventoryInfo">
|
||||||
|
<text class="form-title">物料核对</text>
|
||||||
|
<view class="material-card" v-for="(item, index) in inventoryInfo.materials" :key="item.jobDetailId || index">
|
||||||
|
<view class="material-header">
|
||||||
|
<text class="material-code">{{ item.materialCode }}</text>
|
||||||
|
<text class="diff-badge" :class="{ changed: isChanged(item) }">
|
||||||
|
{{ isChanged(item) ? '有差异' : '一致' }}
|
||||||
|
</text>
|
||||||
|
</view>
|
||||||
|
<text class="material-name">{{ item.materialName || '-' }}</text>
|
||||||
|
<view class="material-meta">
|
||||||
|
<text>批次:{{ item.lotNo || '-' }}</text>
|
||||||
|
<text>账面:{{ item.quantity || 0 }}</text>
|
||||||
|
<text>库存:{{ item.stockQuantity || 0 }}</text>
|
||||||
|
</view>
|
||||||
|
<view class="material-confirm">
|
||||||
|
<text class="material-confirm-label">实盘数量</text>
|
||||||
|
<input class="material-input" v-model="item.actualQuantity" type="number" :placeholder="'账面 ' + item.quantity" />
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="btn-section" v-if="inventoryInfo">
|
||||||
|
<button class="btn btn-primary" @click="submitInventory">提交盘点</button>
|
||||||
|
<button class="btn btn-default" @click="resetForm">重置</button>
|
||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { getInventoryTaskList, getInventoryDetail, confirmInventory } from '@/api/warehouse/inventory'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
scanCode: ''
|
taskNo: '',
|
||||||
|
barcode: '',
|
||||||
|
taskList: [],
|
||||||
|
inventoryInfo: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
if (options.taskNo) {
|
||||||
|
this.taskNo = options.taskNo
|
||||||
|
}
|
||||||
|
this.loadTasks()
|
||||||
|
},
|
||||||
|
onShow() {
|
||||||
|
this.loadTasks()
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
scanInventory() {
|
loadTasks() {
|
||||||
|
var that = this
|
||||||
|
getInventoryTaskList().then(function(res) {
|
||||||
|
that.taskList = res.data || []
|
||||||
|
}).catch(function() {
|
||||||
|
that.taskList = []
|
||||||
|
})
|
||||||
|
},
|
||||||
|
startScan() {
|
||||||
|
var that = this
|
||||||
uni.scanCode({
|
uni.scanCode({
|
||||||
success: res => {
|
onlyFromCamera: false,
|
||||||
this.scanCode = res.result || ''
|
scanType: ['barCode', 'qrCode'],
|
||||||
this.$modal.showToast('扫码成功')
|
success: function(res) {
|
||||||
|
that.barcode = res.result || ''
|
||||||
|
that.handleSearch()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
showReservedTip() {
|
selectTask(item) {
|
||||||
this.$modal.showToast('功能预留')
|
this.taskNo = item.taskNo || ''
|
||||||
|
this.barcode = item.trayCode || ''
|
||||||
|
this.handleSearch()
|
||||||
|
},
|
||||||
|
handleSearch() {
|
||||||
|
if (!this.taskNo && !this.barcode) {
|
||||||
|
this.$modal.msg('请输入任务号或托盘码')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var that = this
|
||||||
|
getInventoryDetail({
|
||||||
|
taskNo: this.taskNo,
|
||||||
|
barcode: this.barcode
|
||||||
|
}).then(function(res) {
|
||||||
|
var data = res.data || {}
|
||||||
|
var materials = (data.materials || []).map(function(item) {
|
||||||
|
return Object.assign({}, item, {
|
||||||
|
actualQuantity: String(item.quantity != null ? item.quantity : 0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
that.inventoryInfo = Object.assign({}, data, { materials: materials })
|
||||||
|
that.taskNo = data.taskNo || that.taskNo
|
||||||
|
that.barcode = data.trayCode || that.barcode
|
||||||
|
that.$modal.msgSuccess('盘点任务获取成功')
|
||||||
|
}).catch(function() {
|
||||||
|
that.inventoryInfo = null
|
||||||
|
})
|
||||||
|
},
|
||||||
|
submitInventory() {
|
||||||
|
if (!this.inventoryInfo || !this.inventoryInfo.materials || this.inventoryInfo.materials.length === 0) {
|
||||||
|
this.$modal.msg('未获取到盘点物料明细')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (this.inventoryInfo.executionPhase !== '5') {
|
||||||
|
this.$modal.msg('WCS 出库完成后才能确认盘点')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var invalid = this.inventoryInfo.materials.find(function(item) {
|
||||||
|
return item.actualQuantity === '' || item.actualQuantity === null || Number(item.actualQuantity) < 0
|
||||||
|
})
|
||||||
|
if (invalid) {
|
||||||
|
this.$modal.msg('请输入每个物料的实盘数量')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var data = {
|
||||||
|
taskNo: this.inventoryInfo.taskNo || this.taskNo,
|
||||||
|
barcode: this.inventoryInfo.trayCode || this.barcode,
|
||||||
|
trayCode: this.inventoryInfo.trayCode || this.barcode,
|
||||||
|
materials: this.inventoryInfo.materials.map(function(item) {
|
||||||
|
return {
|
||||||
|
jobDetailId: item.jobDetailId,
|
||||||
|
stockDetailId: item.stockDetailId,
|
||||||
|
stockpdDetailId: item.stockpdDetailId,
|
||||||
|
quantity: item.actualQuantity
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
var that = this
|
||||||
|
confirmInventory(data).then(function() {
|
||||||
|
that.$modal.msgSuccess('盘点确认成功,已生成回库作业')
|
||||||
|
that.resetForm()
|
||||||
|
that.loadTasks()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
resetForm() {
|
||||||
|
this.taskNo = ''
|
||||||
|
this.barcode = ''
|
||||||
|
this.inventoryInfo = null
|
||||||
|
},
|
||||||
|
calculateActualTotal() {
|
||||||
|
if (!this.inventoryInfo || !this.inventoryInfo.materials) {
|
||||||
|
return '0'
|
||||||
|
}
|
||||||
|
return String(this.inventoryInfo.materials.reduce(function(sum, item) {
|
||||||
|
return sum + Number(item.actualQuantity || 0)
|
||||||
|
}, 0))
|
||||||
|
},
|
||||||
|
isChanged(item) {
|
||||||
|
return Number(item.actualQuantity || 0) !== Number(item.quantity || 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,101 +239,338 @@
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
page {
|
page {
|
||||||
background-color: #f5f7fa;
|
background-color: #f4f6f8;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-container {
|
.page-container {
|
||||||
padding: 24rpx;
|
padding: 24rpx;
|
||||||
|
padding-bottom: 60rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-section {
|
.scan-section,
|
||||||
margin-bottom: 32rpx;
|
.task-card,
|
||||||
}
|
.form-section {
|
||||||
|
|
||||||
.menu-card {
|
|
||||||
background: #fff;
|
background: #fff;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
padding: 32rpx 28rpx;
|
box-shadow: 0 2rpx 10rpx rgba(24, 38, 55, 0.05);
|
||||||
margin-bottom: 20rpx;
|
}
|
||||||
|
|
||||||
|
.scan-section {
|
||||||
|
padding: 28rpx;
|
||||||
|
margin-bottom: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
align-items: flex-start;
|
||||||
|
margin-bottom: 22rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reserve-card {
|
.scan-title {
|
||||||
opacity: 0.88;
|
display: block;
|
||||||
|
font-size: 32rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #243126;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-left {
|
.scan-subtitle {
|
||||||
|
display: block;
|
||||||
|
margin-top: 6rpx;
|
||||||
|
font-size: 23rpx;
|
||||||
|
color: #7c8a80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-btn {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
flex: 1;
|
padding: 8rpx 20rpx;
|
||||||
|
border: 1rpx solid #1f8f4d;
|
||||||
|
border-radius: 8rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-icon {
|
.scan-btn-text {
|
||||||
width: 72rpx;
|
font-size: 24rpx;
|
||||||
height: 72rpx;
|
color: #1f8f4d;
|
||||||
|
margin-left: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
border: 1rpx solid #e5e9ec;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
padding: 0 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-label {
|
||||||
|
width: 120rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #657069;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scan-input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: 76rpx;
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #202724;
|
||||||
|
}
|
||||||
|
|
||||||
|
.query-btn {
|
||||||
|
margin-top: 6rpx;
|
||||||
|
height: 78rpx;
|
||||||
|
line-height: 78rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
background: #1f8f4d;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 29rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-section {
|
||||||
|
margin-bottom: 28rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #25302a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-action {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #1f8f4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.empty-state {
|
||||||
|
background: #fff;
|
||||||
border-radius: 16rpx;
|
border-radius: 16rpx;
|
||||||
|
padding: 72rpx 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-right: 24rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-icon.green {
|
.empty-text {
|
||||||
background: linear-gradient(135deg, #52c41a, #73d13d);
|
font-size: 27rpx;
|
||||||
|
color: #a9b2ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-icon.gray {
|
.task-card {
|
||||||
background: linear-gradient(135deg, #8c8c8c, #bfbfbf);
|
padding: 24rpx;
|
||||||
|
margin-bottom: 18rpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-info {
|
.task-header,
|
||||||
display: flex;
|
.task-footer {
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-title {
|
|
||||||
font-size: 30rpx;
|
|
||||||
font-weight: 500;
|
|
||||||
color: #333;
|
|
||||||
margin-bottom: 8rpx;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-desc {
|
|
||||||
font-size: 24rpx;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-card {
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 16rpx;
|
|
||||||
padding: 28rpx;
|
|
||||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
|
||||||
}
|
|
||||||
|
|
||||||
.result-header {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 14rpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-title {
|
.task-header {
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-type {
|
||||||
font-size: 28rpx;
|
font-size: 28rpx;
|
||||||
font-weight: 500;
|
font-weight: 600;
|
||||||
color: #333;
|
color: #1f8f4d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-code {
|
.task-no,
|
||||||
|
.task-time {
|
||||||
|
font-size: 23rpx;
|
||||||
|
color: #8b9690;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-line {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 8rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-label,
|
||||||
|
.info-label {
|
||||||
font-size: 26rpx;
|
font-size: 26rpx;
|
||||||
color: #52c41a;
|
color: #8b9690;
|
||||||
}
|
}
|
||||||
|
|
||||||
.result-desc {
|
.line-value,
|
||||||
|
.info-value {
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #26302b;
|
||||||
|
max-width: 460rpx;
|
||||||
|
text-align: right;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.highlight {
|
||||||
|
color: #1f8f4d;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-footer {
|
||||||
|
margin-top: 14rpx;
|
||||||
|
padding-top: 14rpx;
|
||||||
|
border-top: 1rpx solid #eef1ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-status {
|
||||||
|
font-size: 22rpx;
|
||||||
|
padding: 5rpx 16rpx;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-status.pending {
|
||||||
|
color: #9b6b00;
|
||||||
|
background: #fff6dc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.task-status.processing {
|
||||||
|
color: #1c6a9e;
|
||||||
|
background: #e8f4ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
padding: 28rpx;
|
||||||
|
margin-bottom: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-title {
|
||||||
|
display: block;
|
||||||
|
font-size: 30rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #25302a;
|
||||||
|
margin-bottom: 20rpx;
|
||||||
|
padding-bottom: 16rpx;
|
||||||
|
border-bottom: 1rpx solid #eef1ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 14rpx 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.phase-tip {
|
||||||
|
margin-top: 16rpx;
|
||||||
|
padding: 14rpx 18rpx;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
background: #fff6dc;
|
||||||
|
color: #9b6b00;
|
||||||
font-size: 24rpx;
|
font-size: 24rpx;
|
||||||
color: #999;
|
}
|
||||||
|
|
||||||
|
.phase-tip.ready {
|
||||||
|
background: #e8f6ee;
|
||||||
|
color: #1f8f4d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-card {
|
||||||
|
padding: 20rpx 0;
|
||||||
|
border-bottom: 1rpx solid #eef1ef;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-card:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-code {
|
||||||
|
font-size: 28rpx;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #25302a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-badge {
|
||||||
|
font-size: 22rpx;
|
||||||
|
color: #1f8f4d;
|
||||||
|
background: #e8f6ee;
|
||||||
|
border-radius: 8rpx;
|
||||||
|
padding: 4rpx 14rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.diff-badge.changed {
|
||||||
|
color: #b54416;
|
||||||
|
background: #fff0e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-name {
|
||||||
|
display: block;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #58625d;
|
||||||
|
margin-bottom: 10rpx;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-meta {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 16rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #8b9690;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-confirm {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 16rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-confirm-label {
|
||||||
|
width: 150rpx;
|
||||||
|
flex-shrink: 0;
|
||||||
|
font-size: 26rpx;
|
||||||
|
color: #657069;
|
||||||
|
}
|
||||||
|
|
||||||
|
.material-input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
height: 70rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border: 1rpx solid #dfe5e1;
|
||||||
|
border-radius: 10rpx;
|
||||||
|
padding: 0 18rpx;
|
||||||
|
font-size: 27rpx;
|
||||||
|
color: #202724;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-section {
|
||||||
|
padding: 8rpx 0 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
font-size: 30rpx;
|
||||||
|
border-radius: 12rpx;
|
||||||
|
margin-bottom: 18rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: #1f8f4d;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-default {
|
||||||
|
background: #fff;
|
||||||
|
color: #657069;
|
||||||
|
border: 1rpx solid #dfe5e1;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import com.ruoyi.in.jobdetail.mapper.MydoJobDetailMapper;
|
|||||||
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
||||||
import com.ruoyi.out.stockout.mapper.OutStockoutMapper;
|
import com.ruoyi.out.stockout.mapper.OutStockoutMapper;
|
||||||
import com.ruoyi.out.stockoutdetail.mapper.OutStockoutDetailMapper;
|
import com.ruoyi.out.stockoutdetail.mapper.OutStockoutDetailMapper;
|
||||||
|
import com.ruoyi.pd.diff.mapper.PdDifferenceRecordMapper;
|
||||||
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.in.job.mapper.MydoJobMapper;
|
import com.ruoyi.in.job.mapper.MydoJobMapper;
|
||||||
@@ -67,6 +68,9 @@ public class MydoJobServiceImpl implements IMydoJobService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private WcsClient wcsClient;
|
private WcsClient wcsClient;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PdDifferenceRecordMapper pdDifferenceRecordMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询作业信息
|
* 查询作业信息
|
||||||
*
|
*
|
||||||
@@ -377,6 +381,9 @@ public class MydoJobServiceImpl implements IMydoJobService
|
|||||||
if (finishResult.isError()) {
|
if (finishResult.isError()) {
|
||||||
return finishResult;
|
return finishResult;
|
||||||
}
|
}
|
||||||
|
if (isInventoryInboundJob(job)) {
|
||||||
|
pdDifferenceRecordMapper.markInboundDifferencesPendingReviewByJobId(jobId);
|
||||||
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
return AjaxResult.error(Convert.toStr(map.get("v_resultmsg")));
|
return AjaxResult.error(Convert.toStr(map.get("v_resultmsg")));
|
||||||
@@ -421,6 +428,11 @@ public class MydoJobServiceImpl implements IMydoJobService
|
|||||||
return job != null && job.getInOrOut() != null && job.getInOrOut() >= 20;
|
return job != null && job.getInOrOut() != null && job.getInOrOut() >= 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isInventoryInboundJob(MydoJob job)
|
||||||
|
{
|
||||||
|
return job != null && (Long.valueOf(10L).equals(job.getInOrOut()) || Long.valueOf(11L).equals(job.getInOrOut()));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WCS 回调取货无货异常。
|
* WCS 回调取货无货异常。
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -43,6 +43,30 @@ public interface PdDifferenceRecordMapper
|
|||||||
*/
|
*/
|
||||||
public int updatePdDifferenceRecord(PdDifferenceRecord pdDifferenceRecord);
|
public int updatePdDifferenceRecord(PdDifferenceRecord pdDifferenceRecord);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核通过后应用盘点差异到库存明细。
|
||||||
|
*
|
||||||
|
* @param pdDifferenceRecord 盘点差异
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int applyApprovedDifference(PdDifferenceRecord pdDifferenceRecord);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 审核通过后刷新库存主表汇总数量。
|
||||||
|
*
|
||||||
|
* @param pdDifferenceRecord 盘点差异
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int refreshApprovedDifferenceStockSummary(PdDifferenceRecord pdDifferenceRecord);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 盘点入库完成后,将对应差异从未入库改为待审核。
|
||||||
|
*
|
||||||
|
* @param jobId 盘点入库作业ID
|
||||||
|
* @return 结果
|
||||||
|
*/
|
||||||
|
public int markInboundDifferencesPendingReviewByJobId(String jobId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除盘点差异
|
* 删除盘点差异
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import java.util.List;
|
|||||||
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
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 org.springframework.transaction.annotation.Transactional;
|
||||||
import com.ruoyi.pd.diff.mapper.PdDifferenceRecordMapper;
|
import com.ruoyi.pd.diff.mapper.PdDifferenceRecordMapper;
|
||||||
import com.ruoyi.pd.diff.domain.PdDifferenceRecord;
|
import com.ruoyi.pd.diff.domain.PdDifferenceRecord;
|
||||||
import com.ruoyi.pd.diff.service.IPdDifferenceRecordService;
|
import com.ruoyi.pd.diff.service.IPdDifferenceRecordService;
|
||||||
@@ -97,10 +98,19 @@ public class PdDifferenceRecordServiceImpl implements IPdDifferenceRecordService
|
|||||||
* 通过差异记录
|
* 通过差异记录
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int approvePdDifferenceRecord(Long id)
|
public int approvePdDifferenceRecord(Long id)
|
||||||
{
|
{
|
||||||
PdDifferenceRecord record = pdDifferenceRecordMapper.selectPdDifferenceRecordById(id);
|
PdDifferenceRecord record = pdDifferenceRecordMapper.selectPdDifferenceRecordById(id);
|
||||||
record.setStatus("1");
|
if (record == null || !"1".equals(record.getStatus())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int applyRows = pdDifferenceRecordMapper.applyApprovedDifference(record);
|
||||||
|
if (applyRows <= 0) {
|
||||||
|
throw new RuntimeException("盘点差异未匹配到可更新库存");
|
||||||
|
}
|
||||||
|
pdDifferenceRecordMapper.refreshApprovedDifferenceStockSummary(record);
|
||||||
|
record.setStatus("2");
|
||||||
return pdDifferenceRecordMapper.updatePdDifferenceRecord(record);
|
return pdDifferenceRecordMapper.updatePdDifferenceRecord(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +121,10 @@ public class PdDifferenceRecordServiceImpl implements IPdDifferenceRecordService
|
|||||||
public int rejectPdDifferenceRecord(Long id)
|
public int rejectPdDifferenceRecord(Long id)
|
||||||
{
|
{
|
||||||
PdDifferenceRecord record = pdDifferenceRecordMapper.selectPdDifferenceRecordById(id);
|
PdDifferenceRecord record = pdDifferenceRecordMapper.selectPdDifferenceRecordById(id);
|
||||||
record.setStatus("2");
|
if (record == null || !"1".equals(record.getStatus())) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
record.setStatus("3");
|
||||||
return pdDifferenceRecordMapper.updatePdDifferenceRecord(record);
|
return pdDifferenceRecordMapper.updatePdDifferenceRecord(record);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,26 @@ package com.ruoyi.pd.stockpd.service.impl;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.math.BigDecimal;
|
||||||
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 org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import com.ruoyi.bas.id.job.service.JobIdService;
|
import com.ruoyi.bas.id.job.service.JobIdService;
|
||||||
|
import com.ruoyi.bas.id.taskno.service.TaskNoService;
|
||||||
|
import com.ruoyi.bas.stock.domain.BasStockDetail;
|
||||||
|
import com.ruoyi.bas.stock.mapper.BasStockDetailMapper;
|
||||||
|
import com.ruoyi.bas.stationpoint.domain.BasStationPoint;
|
||||||
|
import com.ruoyi.bas.stationpoint.service.IBasStationPointService;
|
||||||
import com.ruoyi.common.PdStockpdStatusEnum;
|
import com.ruoyi.common.PdStockpdStatusEnum;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.core.text.Convert;
|
import com.ruoyi.common.core.text.Convert;
|
||||||
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
|
import com.ruoyi.in.job.domain.MydoJob;
|
||||||
|
import com.ruoyi.in.job.service.IMydoJobService;
|
||||||
|
import com.ruoyi.in.jobdetail.domain.MydoJobDetail;
|
||||||
|
import com.ruoyi.in.jobdetail.service.IMydoJobDetailService;
|
||||||
import com.ruoyi.system.mapper.SysDeptMapper;
|
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||||
import com.ruoyi.pd.stockpd.mapper.PdStockpdMapper;
|
import com.ruoyi.pd.stockpd.mapper.PdStockpdMapper;
|
||||||
import com.ruoyi.pd.stockpd.domain.PdStockpd;
|
import com.ruoyi.pd.stockpd.domain.PdStockpd;
|
||||||
@@ -18,6 +30,7 @@ import com.ruoyi.pd.stockpd.domain.PdStockpdSaveDTO;
|
|||||||
import com.ruoyi.pd.stockpd.service.IPdStockpdService;
|
import com.ruoyi.pd.stockpd.service.IPdStockpdService;
|
||||||
import com.ruoyi.pd.stockpddetail.mapper.PdStockpdDetailMapper;
|
import com.ruoyi.pd.stockpddetail.mapper.PdStockpdDetailMapper;
|
||||||
import com.ruoyi.pd.stockpddetail.domain.PdStockpdDetail;
|
import com.ruoyi.pd.stockpddetail.domain.PdStockpdDetail;
|
||||||
|
import com.ruoyi.pda.mapper.PdaMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 盘点单据主信息Service业务层处理
|
* 盘点单据主信息Service业务层处理
|
||||||
@@ -28,6 +41,10 @@ import com.ruoyi.pd.stockpddetail.domain.PdStockpdDetail;
|
|||||||
@Service
|
@Service
|
||||||
public class PdStockpdServiceImpl implements IPdStockpdService
|
public class PdStockpdServiceImpl implements IPdStockpdService
|
||||||
{
|
{
|
||||||
|
private static final long MATERIAL_INVENTORY_OUT_TYPE = 30L;
|
||||||
|
private static final long LOCATION_INVENTORY_OUT_TYPE = 31L;
|
||||||
|
private static final String INVENTORY_OUT_TASK_NO_TYPE = "22";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PdStockpdMapper pdStockpdMapper;
|
private PdStockpdMapper pdStockpdMapper;
|
||||||
|
|
||||||
@@ -40,6 +57,24 @@ public class PdStockpdServiceImpl implements IPdStockpdService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private JobIdService jobIdService;
|
private JobIdService jobIdService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private TaskNoService taskNoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BasStockDetailMapper basStockDetailMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IBasStationPointService basStationPointService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMydoJobService mydoJobService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private IMydoJobDetailService mydoJobDetailService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PdaMapper pdaMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询盘点单据主信息
|
* 查询盘点单据主信息
|
||||||
*
|
*
|
||||||
@@ -179,22 +214,73 @@ public class PdStockpdServiceImpl implements IPdStockpdService
|
|||||||
* 自动分配盘点单据
|
* 自动分配盘点单据
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public AjaxResult autoAssignPdStockpd(String stockpdId)
|
public AjaxResult autoAssignPdStockpd(String stockpdId)
|
||||||
{
|
{
|
||||||
StringBuilder str = new StringBuilder();
|
PdStockpd stockpd = pdStockpdMapper.selectPdStockpdByStockpdId(stockpdId);
|
||||||
|
if (stockpd == null) {
|
||||||
|
return AjaxResult.error("盘点单据不存在");
|
||||||
|
}
|
||||||
|
if (!PdStockpdStatusEnum.AUDIT.getCode().equals(stockpd.getStatus())
|
||||||
|
&& !PdStockpdStatusEnum.RUNNING.getCode().equals(stockpd.getStatus())) {
|
||||||
|
return AjaxResult.error("只有已审核或执行中的盘点单据允许生成盘点出库作业");
|
||||||
|
}
|
||||||
|
|
||||||
PdStockpdDetail query = new PdStockpdDetail();
|
PdStockpdDetail query = new PdStockpdDetail();
|
||||||
query.setStockpdId(stockpdId);
|
query.setStockpdId(stockpdId);
|
||||||
List<PdStockpdDetail> details = pdStockpdDetailMapper.selectPdStockpdDetailList(query);
|
List<PdStockpdDetail> details = pdStockpdDetailMapper.selectPdStockpdDetailList(query);
|
||||||
for (PdStockpdDetail detail : details) {
|
if (details == null || details.isEmpty()) {
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
return AjaxResult.error("盘点单据没有明细");
|
||||||
map.put("v_stockpd_detail_id", detail.getStockpdDetailId());
|
|
||||||
pdStockpdMapper.autoAssignPdStockpdByProc(map);
|
|
||||||
if (Convert.toStr(map.get("v_result")).equals("10")){
|
|
||||||
str.append(detail.getStockpdDetailId()).append(Convert.toStr(map.get("v_result_msg"))).append("|");
|
|
||||||
}else {
|
|
||||||
str.append(detail.getStockpdDetailId()).append(Convert.toStr(map.get("v_result_msg"))).append("|");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BasStationPoint exitPoint = selectDefaultOutboundStationPoint(stockpd.getWarehouseId());
|
||||||
|
StringBuilder str = new StringBuilder("盘点出库作业生成成功:");
|
||||||
|
for (PdStockpdDetail detail : details) {
|
||||||
|
BasStockDetail stockDetail = resolveInventoryStockDetail(stockpd, detail);
|
||||||
|
BigDecimal quantity = resolveInventoryQuantity(detail, stockDetail);
|
||||||
|
if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new RuntimeException("盘点明细数量必须大于0:" + detail.getStockpdDetailId());
|
||||||
|
}
|
||||||
|
|
||||||
|
MydoJob job = buildInventoryOutboundJob(stockpd, stockDetail, exitPoint);
|
||||||
|
if (mydoJobService.insertMydoJob(job) <= 0) {
|
||||||
|
throw new RuntimeException("盘点出库作业生成失败:" + detail.getStockpdDetailId());
|
||||||
|
}
|
||||||
|
|
||||||
|
MydoJobDetail jobDetail = buildInventoryOutboundDetail(job, stockpd, detail, stockDetail, quantity);
|
||||||
|
if (mydoJobDetailService.insertMydoJobDetail(jobDetail) <= 0) {
|
||||||
|
throw new RuntimeException("盘点出库作业明细生成失败:" + detail.getStockpdDetailId());
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, Object> reserveMap = new HashMap<>();
|
||||||
|
reserveMap.put("stockDetailId", stockDetail.getDetailId());
|
||||||
|
reserveMap.put("stockId", stockDetail.getStockId());
|
||||||
|
reserveMap.put("jobDetailId", jobDetail.getJobDetailId());
|
||||||
|
reserveMap.put("quantity", quantity);
|
||||||
|
if (pdaMapper.reserveInventoryStockDetail(reserveMap) <= 0) {
|
||||||
|
throw new RuntimeException("盘点库存已被占用或可用库存不足:" + detail.getStockpdDetailId());
|
||||||
|
}
|
||||||
|
|
||||||
|
HashMap<String, Object> cargoMap = new HashMap<>();
|
||||||
|
cargoMap.put("stockId", stockDetail.getStockId());
|
||||||
|
cargoMap.put("cargoSpaceId", stockDetail.getCargoSpaceId());
|
||||||
|
if (pdaMapper.lockInventoryOutboundCargoSpace(cargoMap) <= 0) {
|
||||||
|
throw new RuntimeException("盘点出库货位锁定失败:" + detail.getStockpdDetailId());
|
||||||
|
}
|
||||||
|
|
||||||
|
AjaxResult pushResult = mydoJobService.pushOutJobToWcs(job.getJobId());
|
||||||
|
if (pushResult == null || pushResult.isError()) {
|
||||||
|
throw new RuntimeException(pushResult == null ? "WCS盘点出库作业下发失败" : Convert.toStr(pushResult.get(AjaxResult.MSG_TAG)));
|
||||||
|
}
|
||||||
|
|
||||||
|
updateAssignedInventoryDetail(detail, stockDetail, quantity);
|
||||||
|
str.append(job.getJobId()).append("|");
|
||||||
|
}
|
||||||
|
PdStockpd update = new PdStockpd();
|
||||||
|
update.setStockpdId(stockpdId);
|
||||||
|
update.setStatus(PdStockpdStatusEnum.RUNNING.getCode());
|
||||||
|
update.setStartDate(new Date());
|
||||||
|
pdStockpdMapper.updatePdStockpd(update);
|
||||||
return AjaxResult.success(str);
|
return AjaxResult.success(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,10 +323,143 @@ public class PdStockpdServiceImpl implements IPdStockpdService
|
|||||||
detail.setAllotNum(0L);
|
detail.setAllotNum(0L);
|
||||||
detail.setAssignNum(0L);
|
detail.setAssignNum(0L);
|
||||||
detail.setStockpdId(saveDTO.getStockpdId());
|
detail.setStockpdId(saveDTO.getStockpdId());
|
||||||
|
if (!StringUtils.hasText(detail.getWarehouseId())) {
|
||||||
|
detail.setWarehouseId(saveDTO.getWarehouseId());
|
||||||
|
}
|
||||||
|
if (!StringUtils.hasText(detail.getWarehouseName())) {
|
||||||
|
detail.setWarehouseName(saveDTO.getWarehouseName());
|
||||||
|
}
|
||||||
pdStockpdDetailMapper.insertPdStockpdDetail(detail);
|
pdStockpdDetailMapper.insertPdStockpdDetail(detail);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return saveDTO.getStockpdId();
|
return saveDTO.getStockpdId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private BasStockDetail resolveInventoryStockDetail(PdStockpd stockpd, PdStockpdDetail detail) {
|
||||||
|
BasStockDetail stockDetail = null;
|
||||||
|
if (StringUtils.hasText(detail.getStockDetailId())) {
|
||||||
|
stockDetail = basStockDetailMapper.selectBasStockDetailByDetailId(detail.getStockDetailId());
|
||||||
|
}
|
||||||
|
if (stockDetail == null) {
|
||||||
|
BasStockDetail query = new BasStockDetail();
|
||||||
|
query.setStockId(detail.getStockId());
|
||||||
|
query.setTrayCode(detail.getTrayCode());
|
||||||
|
query.setWarehouseId(StringUtils.hasText(detail.getWarehouseId()) ? detail.getWarehouseId() : stockpd.getWarehouseId());
|
||||||
|
query.setCargoSpaceId(detail.getCargoSpaceId());
|
||||||
|
query.setProductId(detail.getProductId());
|
||||||
|
List<BasStockDetail> stockDetails = basStockDetailMapper.selectBasStockDetailList(query);
|
||||||
|
if (stockDetails != null && !stockDetails.isEmpty()) {
|
||||||
|
stockDetail = stockDetails.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stockDetail == null) {
|
||||||
|
throw new RuntimeException("未找到盘点库存明细:" + detail.getStockpdDetailId());
|
||||||
|
}
|
||||||
|
return stockDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BigDecimal resolveInventoryQuantity(PdStockpdDetail detail, BasStockDetail stockDetail) {
|
||||||
|
BigDecimal quantity = detail.getQuantity() == null ? null : BigDecimal.valueOf(detail.getQuantity());
|
||||||
|
if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
quantity = stockDetail.getAvailableQuantity();
|
||||||
|
}
|
||||||
|
if (quantity == null || quantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
quantity = stockDetail.getQuantity();
|
||||||
|
}
|
||||||
|
BigDecimal availableQuantity = stockDetail.getAvailableQuantity();
|
||||||
|
if (availableQuantity != null && availableQuantity.compareTo(BigDecimal.ZERO) > 0
|
||||||
|
&& quantity.compareTo(availableQuantity) > 0) {
|
||||||
|
throw new RuntimeException("盘点数量不能大于可用库存:" + detail.getStockpdDetailId());
|
||||||
|
}
|
||||||
|
return quantity == null ? BigDecimal.ZERO : quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private BasStationPoint selectDefaultOutboundStationPoint(String warehouseId) {
|
||||||
|
BasStationPoint query = new BasStationPoint();
|
||||||
|
query.setWarehouseId(warehouseId);
|
||||||
|
query.setStatus("0");
|
||||||
|
query.setPointStatus("0");
|
||||||
|
List<BasStationPoint> pointList = basStationPointService.selectBasStationPointList(query);
|
||||||
|
if (pointList != null) {
|
||||||
|
for (BasStationPoint point : pointList) {
|
||||||
|
if (point != null && ("2".equals(point.getPointType()) || "3".equals(point.getPointType()))) {
|
||||||
|
return point;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RuntimeException("当前仓库未配置可用出库点位");
|
||||||
|
}
|
||||||
|
|
||||||
|
private MydoJob buildInventoryOutboundJob(PdStockpd stockpd, BasStockDetail stockDetail, BasStationPoint exitPoint) {
|
||||||
|
String jobId = jobIdService.getId("PC");
|
||||||
|
String taskNo = taskNoService.getTaskNo(INVENTORY_OUT_TASK_NO_TYPE);
|
||||||
|
MydoJob job = new MydoJob();
|
||||||
|
job.setJobId(jobId);
|
||||||
|
job.setTaskNo(StringUtils.hasText(taskNo) ? taskNo : jobId);
|
||||||
|
job.setInOrOut(resolveInventoryOutType(stockpd));
|
||||||
|
job.setStatus("1");
|
||||||
|
job.setExecutionPhase("0");
|
||||||
|
job.setTrayCode(stockDetail.getTrayCode());
|
||||||
|
job.setWarehouseId(StringUtils.hasText(stockDetail.getWarehouseId()) ? stockDetail.getWarehouseId() : stockpd.getWarehouseId());
|
||||||
|
job.setWarehouseName(StringUtils.hasText(stockDetail.getWarehouseName()) ? stockDetail.getWarehouseName() : stockpd.getWarehouseName());
|
||||||
|
job.setCargoSpaceId(stockDetail.getCargoSpaceId());
|
||||||
|
job.setCargoSpaceName(stockDetail.getCargoSpaceName());
|
||||||
|
job.setExitId(exitPoint.getPointId());
|
||||||
|
job.setPriority(10L);
|
||||||
|
job.setHeight(BigDecimal.ZERO);
|
||||||
|
job.setWeight(BigDecimal.ZERO);
|
||||||
|
copyLoginUser(job);
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long resolveInventoryOutType(PdStockpd stockpd) {
|
||||||
|
return "2".equals(stockpd.getPdType()) ? LOCATION_INVENTORY_OUT_TYPE : MATERIAL_INVENTORY_OUT_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MydoJobDetail buildInventoryOutboundDetail(MydoJob job, PdStockpd stockpd, PdStockpdDetail detail,
|
||||||
|
BasStockDetail stockDetail, BigDecimal quantity) {
|
||||||
|
MydoJobDetail jobDetail = new MydoJobDetail();
|
||||||
|
jobDetail.setJobDetailId(job.getJobId() + "-1");
|
||||||
|
jobDetail.setJobId(job.getJobId());
|
||||||
|
jobDetail.setStockId(stockDetail.getStockId());
|
||||||
|
jobDetail.setLotNo(stockDetail.getLotNo());
|
||||||
|
jobDetail.setInDate(DateUtils.getTime());
|
||||||
|
jobDetail.setInOrOutId(stockpd.getStockpdId());
|
||||||
|
jobDetail.setInOrOutDId(detail.getStockpdDetailId());
|
||||||
|
jobDetail.setProductId(stockDetail.getProductId());
|
||||||
|
jobDetail.setProductName(stockDetail.getProductName());
|
||||||
|
jobDetail.setStockQuantity(stockDetail.getQuantity());
|
||||||
|
jobDetail.setOutQuantity(quantity);
|
||||||
|
jobDetail.setStockinDetailId(stockDetail.getDetailId());
|
||||||
|
return jobDetail;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAssignedInventoryDetail(PdStockpdDetail detail, BasStockDetail stockDetail, BigDecimal quantity) {
|
||||||
|
PdStockpdDetail update = new PdStockpdDetail();
|
||||||
|
update.setStockpdDetailId(detail.getStockpdDetailId());
|
||||||
|
update.setStockId(stockDetail.getStockId());
|
||||||
|
update.setStockDetailId(stockDetail.getDetailId());
|
||||||
|
update.setTrayCode(stockDetail.getTrayCode());
|
||||||
|
update.setCargoSpaceId(stockDetail.getCargoSpaceId());
|
||||||
|
update.setCargoSpaceName(stockDetail.getCargoSpaceName());
|
||||||
|
update.setWarehouseId(stockDetail.getWarehouseId());
|
||||||
|
update.setWarehouseName(stockDetail.getWarehouseName());
|
||||||
|
update.setProductId(stockDetail.getProductId());
|
||||||
|
update.setProductName(stockDetail.getProductName());
|
||||||
|
update.setQuantity(quantity.longValue());
|
||||||
|
update.setAllotNum(quantity.longValue());
|
||||||
|
update.setAssignNum(0L);
|
||||||
|
pdStockpdDetailMapper.updatePdStockpdDetail(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void copyLoginUser(MydoJob job) {
|
||||||
|
try {
|
||||||
|
job.setUserId(SecurityUtils.getUserId());
|
||||||
|
job.setDeptId(SecurityUtils.getDeptId());
|
||||||
|
job.setUserName(SecurityUtils.getUsername());
|
||||||
|
} catch (RuntimeException ignored) {
|
||||||
|
// Unit tests and external callbacks may run without a Spring Security context.
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,30 @@ public class PdStockpdDetail extends BaseEntity
|
|||||||
@Excel(name = "托盘码")
|
@Excel(name = "托盘码")
|
||||||
private String trayCode;
|
private String trayCode;
|
||||||
|
|
||||||
|
/** 库存ID */
|
||||||
|
@Excel(name = "库存ID")
|
||||||
|
private String stockId;
|
||||||
|
|
||||||
|
/** 库存明细ID */
|
||||||
|
@Excel(name = "库存明细ID")
|
||||||
|
private String stockDetailId;
|
||||||
|
|
||||||
|
/** 货位ID */
|
||||||
|
@Excel(name = "货位ID")
|
||||||
|
private String cargoSpaceId;
|
||||||
|
|
||||||
|
/** 货位名称 */
|
||||||
|
@Excel(name = "货位名称")
|
||||||
|
private String cargoSpaceName;
|
||||||
|
|
||||||
|
/** 仓库ID */
|
||||||
|
@Excel(name = "仓库ID")
|
||||||
|
private String warehouseId;
|
||||||
|
|
||||||
|
/** 仓库名称 */
|
||||||
|
@Excel(name = "仓库名称")
|
||||||
|
private String warehouseName;
|
||||||
|
|
||||||
/** 物料编码 */
|
/** 物料编码 */
|
||||||
@Excel(name = "物料编码")
|
@Excel(name = "物料编码")
|
||||||
private String productId;
|
private String productId;
|
||||||
@@ -86,6 +110,66 @@ public class PdStockpdDetail extends BaseEntity
|
|||||||
return trayCode;
|
return trayCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setStockId(String stockId)
|
||||||
|
{
|
||||||
|
this.stockId = stockId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStockId()
|
||||||
|
{
|
||||||
|
return stockId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStockDetailId(String stockDetailId)
|
||||||
|
{
|
||||||
|
this.stockDetailId = stockDetailId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStockDetailId()
|
||||||
|
{
|
||||||
|
return stockDetailId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCargoSpaceId(String cargoSpaceId)
|
||||||
|
{
|
||||||
|
this.cargoSpaceId = cargoSpaceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCargoSpaceId()
|
||||||
|
{
|
||||||
|
return cargoSpaceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCargoSpaceName(String cargoSpaceName)
|
||||||
|
{
|
||||||
|
this.cargoSpaceName = cargoSpaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCargoSpaceName()
|
||||||
|
{
|
||||||
|
return cargoSpaceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWarehouseId(String warehouseId)
|
||||||
|
{
|
||||||
|
this.warehouseId = warehouseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWarehouseId()
|
||||||
|
{
|
||||||
|
return warehouseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWarehouseName(String warehouseName)
|
||||||
|
{
|
||||||
|
this.warehouseName = warehouseName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getWarehouseName()
|
||||||
|
{
|
||||||
|
return warehouseName;
|
||||||
|
}
|
||||||
|
|
||||||
public void setProductId(String productId)
|
public void setProductId(String productId)
|
||||||
{
|
{
|
||||||
this.productId = productId;
|
this.productId = productId;
|
||||||
@@ -142,6 +226,12 @@ public class PdStockpdDetail extends BaseEntity
|
|||||||
.append("stockpdDetailId", getStockpdDetailId())
|
.append("stockpdDetailId", getStockpdDetailId())
|
||||||
.append("stockpdId", getStockpdId())
|
.append("stockpdId", getStockpdId())
|
||||||
.append("trayCode", getTrayCode())
|
.append("trayCode", getTrayCode())
|
||||||
|
.append("stockId", getStockId())
|
||||||
|
.append("stockDetailId", getStockDetailId())
|
||||||
|
.append("cargoSpaceId", getCargoSpaceId())
|
||||||
|
.append("cargoSpaceName", getCargoSpaceName())
|
||||||
|
.append("warehouseId", getWarehouseId())
|
||||||
|
.append("warehouseName", getWarehouseName())
|
||||||
.append("productId", getProductId())
|
.append("productId", getProductId())
|
||||||
.append("productName", getProductName())
|
.append("productName", getProductName())
|
||||||
.append("quantity", getQuantity())
|
.append("quantity", getQuantity())
|
||||||
|
|||||||
@@ -192,6 +192,15 @@ public class PdaController extends BaseController {
|
|||||||
return AjaxResult.success(pdaService.outboundTaskList(query));
|
return AjaxResult.success(pdaService.outboundTaskList(query));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 盘点待确认任务列表。
|
||||||
|
*/
|
||||||
|
@GetMapping("/inventoryTaskList")
|
||||||
|
@PreAuthorize("@ss.hasPermi('pd:stockpd:list')")
|
||||||
|
public AjaxResult inventoryTaskList(@RequestParam Map<String, Object> query) {
|
||||||
|
return AjaxResult.success(pdaService.inventoryTaskList(query));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDA 查询当前仓库库内空托按条码头分组的数量。
|
* PDA 查询当前仓库库内空托按条码头分组的数量。
|
||||||
*/
|
*/
|
||||||
@@ -246,6 +255,19 @@ public class PdaController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 扫码查询盘点任务明细。
|
||||||
|
*/
|
||||||
|
@GetMapping("/inventoryDetail")
|
||||||
|
@PreAuthorize("@ss.hasPermi('pd:stockpd:list')")
|
||||||
|
public AjaxResult inventoryDetail(@RequestParam Map<String, Object> query) {
|
||||||
|
try {
|
||||||
|
return AjaxResult.success(pdaService.inventoryDetail(query));
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return AjaxResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDA 确认出库。
|
* PDA 确认出库。
|
||||||
*/
|
*/
|
||||||
@@ -261,4 +283,19 @@ public class PdaController extends BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 确认盘点。
|
||||||
|
*/
|
||||||
|
@PostMapping("/inventoryConfirm")
|
||||||
|
@PreAuthorize("@ss.hasPermi('pd:stockpd:edit')")
|
||||||
|
@Log(title = "PDA盘点确认", businessType = BusinessType.UPDATE)
|
||||||
|
public AjaxResult inventoryConfirm(@RequestBody Map<String, Object> data) {
|
||||||
|
try {
|
||||||
|
pdaService.confirmInventory(data);
|
||||||
|
return AjaxResult.success();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
return AjaxResult.error(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,16 +55,36 @@ public interface PdaMapper {
|
|||||||
*/
|
*/
|
||||||
List<HashMap<String, Object>> outboundTaskList(HashMap<String, Object> map);
|
List<HashMap<String, Object>> outboundTaskList(HashMap<String, Object> map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 盘点待确认任务列表。
|
||||||
|
*/
|
||||||
|
List<HashMap<String, Object>> inventoryTaskList(HashMap<String, Object> map);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDA 扫码查询出库任务明细。
|
* PDA 扫码查询出库任务明细。
|
||||||
*/
|
*/
|
||||||
HashMap<String, Object> selectOutboundDetail(HashMap<String, Object> map);
|
HashMap<String, Object> selectOutboundDetail(HashMap<String, Object> map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 扫码查询盘点出库任务明细。
|
||||||
|
*/
|
||||||
|
HashMap<String, Object> selectInventoryDetail(HashMap<String, Object> map);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询出库托盘上的作业物料明细。
|
* 查询出库托盘上的作业物料明细。
|
||||||
*/
|
*/
|
||||||
List<HashMap<String, Object>> selectOutboundTrayMaterials(HashMap<String, Object> map);
|
List<HashMap<String, Object>> selectOutboundTrayMaterials(HashMap<String, Object> map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询盘点托盘上的作业物料明细。
|
||||||
|
*/
|
||||||
|
List<HashMap<String, Object>> selectInventoryTrayMaterials(HashMap<String, Object> map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询盘点出库对应的盘点入库作业,防止 PDA 重复确认重复生成回库作业。
|
||||||
|
*/
|
||||||
|
HashMap<String, Object> selectInventoryInboundJobByOutboundJobId(@Param("outboundJobId") String outboundJobId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询出库确认后托盘上仍有库存的物料。
|
* 查询出库确认后托盘上仍有库存的物料。
|
||||||
*/
|
*/
|
||||||
@@ -95,8 +115,18 @@ public interface PdaMapper {
|
|||||||
*/
|
*/
|
||||||
int reserveEmptyTrayStockDetail(HashMap<String, Object> map);
|
int reserveEmptyTrayStockDetail(HashMap<String, Object> map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 预占盘点库存明细,避免重复生成盘点出库作业。
|
||||||
|
*/
|
||||||
|
int reserveInventoryStockDetail(HashMap<String, Object> map);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将空托所在货位标记为出库锁定。
|
* 将空托所在货位标记为出库锁定。
|
||||||
*/
|
*/
|
||||||
int lockEmptyTrayCargoSpace(HashMap<String, Object> map);
|
int lockEmptyTrayCargoSpace(HashMap<String, Object> map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 将盘点托盘所在货位标记为出库锁定。
|
||||||
|
*/
|
||||||
|
int lockInventoryOutboundCargoSpace(HashMap<String, Object> map);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -131,6 +131,14 @@ public interface PdaService {
|
|||||||
*/
|
*/
|
||||||
List<Map<String, Object>> outboundTaskList(Map<String, Object> query);
|
List<Map<String, Object>> outboundTaskList(Map<String, Object> query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 盘点待确认任务列表。
|
||||||
|
*
|
||||||
|
* @param query 查询条件
|
||||||
|
* @return 盘点任务列表
|
||||||
|
*/
|
||||||
|
List<Map<String, Object>> inventoryTaskList(Map<String, Object> query);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDA 扫码查询出库任务明细。
|
* PDA 扫码查询出库任务明细。
|
||||||
*
|
*
|
||||||
@@ -139,6 +147,14 @@ public interface PdaService {
|
|||||||
*/
|
*/
|
||||||
Map<String, Object> outboundDetail(Map<String, Object> query);
|
Map<String, Object> outboundDetail(Map<String, Object> query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 扫码查询盘点任务明细。
|
||||||
|
*
|
||||||
|
* @param query 查询条件,包含任务号和托盘码
|
||||||
|
* @return 盘点任务明细
|
||||||
|
*/
|
||||||
|
Map<String, Object> inventoryDetail(Map<String, Object> query);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PDA 确认出库。
|
* PDA 确认出库。
|
||||||
*
|
*
|
||||||
@@ -146,4 +162,11 @@ public interface PdaService {
|
|||||||
*/
|
*/
|
||||||
void confirmOutbound(Map<String, Object> data);
|
void confirmOutbound(Map<String, Object> data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PDA 确认盘点。
|
||||||
|
*
|
||||||
|
* @param data 确认数据
|
||||||
|
*/
|
||||||
|
void confirmInventory(Map<String, Object> data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ import com.ruoyi.in.stockin.domain.InStockin;
|
|||||||
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
||||||
import com.ruoyi.in.sotckindetail.domain.InStockinDetail;
|
import com.ruoyi.in.sotckindetail.domain.InStockinDetail;
|
||||||
import com.ruoyi.in.sotckindetail.mapper.InStockinDetailMapper;
|
import com.ruoyi.in.sotckindetail.mapper.InStockinDetailMapper;
|
||||||
|
import com.ruoyi.pd.commit.domain.PdCommitRecord;
|
||||||
|
import com.ruoyi.pd.commit.mapper.PdCommitRecordMapper;
|
||||||
|
import com.ruoyi.pd.diff.domain.PdDifferenceRecord;
|
||||||
|
import com.ruoyi.pd.diff.mapper.PdDifferenceRecordMapper;
|
||||||
|
import com.ruoyi.pd.stockpddetail.domain.PdStockpdDetail;
|
||||||
|
import com.ruoyi.pd.stockpddetail.mapper.PdStockpdDetailMapper;
|
||||||
import com.ruoyi.pda.domain.AddInJobRequest;
|
import com.ruoyi.pda.domain.AddInJobRequest;
|
||||||
import com.ruoyi.pda.domain.BindTrayRequest;
|
import com.ruoyi.pda.domain.BindTrayRequest;
|
||||||
import com.ruoyi.pda.domain.EmptyTrayOutboundRequest;
|
import com.ruoyi.pda.domain.EmptyTrayOutboundRequest;
|
||||||
@@ -51,6 +57,8 @@ public class PdaServiceImpl implements PdaService {
|
|||||||
private static final String EMPTY_TRAY_IN_TASK_NO_TYPE = "6";
|
private static final String EMPTY_TRAY_IN_TASK_NO_TYPE = "6";
|
||||||
private static final String EMPTY_TRAY_OUT_TASK_NO_TYPE = "20";
|
private static final String EMPTY_TRAY_OUT_TASK_NO_TYPE = "20";
|
||||||
private static final BigDecimal ONE_EMPTY_TRAY = BigDecimal.ONE;
|
private static final BigDecimal ONE_EMPTY_TRAY = BigDecimal.ONE;
|
||||||
|
private static final long MATERIAL_INVENTORY_OUT_TYPE = 30L;
|
||||||
|
private static final long LOCATION_INVENTORY_OUT_TYPE = 31L;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PdaMapper pdaMapper;
|
private PdaMapper pdaMapper;
|
||||||
@@ -82,6 +90,15 @@ public class PdaServiceImpl implements PdaService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private TaskNoService taskNoService;
|
private TaskNoService taskNoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PdCommitRecordMapper pdCommitRecordMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PdDifferenceRecordMapper pdDifferenceRecordMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PdStockpdDetailMapper pdStockpdDetailMapper;
|
||||||
|
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
// 入库待处理任务列表
|
// 入库待处理任务列表
|
||||||
// ─────────────────────────────────────────────
|
// ─────────────────────────────────────────────
|
||||||
@@ -653,6 +670,18 @@ public class PdaServiceImpl implements PdaService {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Map<String, Object>> inventoryTaskList(Map<String, Object> query) {
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
if (query != null) {
|
||||||
|
map.putAll(query);
|
||||||
|
}
|
||||||
|
List<HashMap<String, Object>> rows = pdaMapper.inventoryTaskList(map);
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
result.addAll(rows);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, Object> outboundDetail(Map<String, Object> query) {
|
public Map<String, Object> outboundDetail(Map<String, Object> query) {
|
||||||
HashMap<String, Object> map = new HashMap<>();
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
@@ -670,6 +699,23 @@ public class PdaServiceImpl implements PdaService {
|
|||||||
return detail;
|
return detail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> inventoryDetail(Map<String, Object> query) {
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
if (query != null) {
|
||||||
|
map.putAll(query);
|
||||||
|
}
|
||||||
|
HashMap<String, Object> detail = pdaMapper.selectInventoryDetail(map);
|
||||||
|
if (detail == null || detail.isEmpty()) {
|
||||||
|
throw new RuntimeException("未找到对应盘点任务");
|
||||||
|
}
|
||||||
|
HashMap<String, Object> materialQuery = new HashMap<>();
|
||||||
|
materialQuery.put("jobId", detail.get("jobId"));
|
||||||
|
List<HashMap<String, Object>> materials = pdaMapper.selectInventoryTrayMaterials(materialQuery);
|
||||||
|
detail.put("materials", materials == null ? new ArrayList<>() : materials);
|
||||||
|
return detail;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void confirmOutbound(Map<String, Object> data) {
|
public void confirmOutbound(Map<String, Object> data) {
|
||||||
@@ -691,6 +737,224 @@ public class PdaServiceImpl implements PdaService {
|
|||||||
createReturnInboundJobIfNeeded(outboundJob);
|
createReturnInboundJobIfNeeded(outboundJob);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void confirmInventory(Map<String, Object> data) {
|
||||||
|
Map<String, Object> detail = inventoryDetail(data);
|
||||||
|
if (!"5".equals(Convert.toStr(detail.get("executionPhase")))) {
|
||||||
|
throw new RuntimeException("盘点出库未到达出口,不能扫码确认");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<HashMap<String, Object>> materials = detail.get("materials") instanceof List<?>
|
||||||
|
? (List<HashMap<String, Object>>) detail.get("materials")
|
||||||
|
: new ArrayList<>();
|
||||||
|
if (materials.isEmpty()) {
|
||||||
|
throw new RuntimeException("盘点作业无物料明细");
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map<String, Object>> requestMaterials = normalizeInventoryRequestMaterials(data, materials);
|
||||||
|
for (HashMap<String, Object> material : materials) {
|
||||||
|
Map<String, Object> requestMaterial = findInventoryRequestMaterial(requestMaterials, material);
|
||||||
|
BigDecimal oldQuantity = toBigDecimal(firstNotBlank(mapValue(material, "quantity"), mapValue(material, "stockQuantity")));
|
||||||
|
BigDecimal actualQuantity = toBigDecimal(firstNotBlank(
|
||||||
|
mapValue(requestMaterial, "actualQuantity"),
|
||||||
|
mapValue(requestMaterial, "quantity")));
|
||||||
|
if (actualQuantity.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
throw new RuntimeException("盘点数量不能小于0");
|
||||||
|
}
|
||||||
|
insertInventoryCommitRecord(detail, material, oldQuantity, actualQuantity);
|
||||||
|
if (oldQuantity.compareTo(actualQuantity) != 0) {
|
||||||
|
insertInventoryDifferenceRecord(detail, material, oldQuantity, actualQuantity);
|
||||||
|
}
|
||||||
|
updateInventoryStockpdDetail(detail, material, oldQuantity, actualQuantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
String jobId = Convert.toStr(detail.get("jobId"));
|
||||||
|
MydoJob outboundJob = mydoJobService.selectMydoJobByJobId(jobId);
|
||||||
|
AjaxResult result = mydoJobService.completeJob(jobId, "2");
|
||||||
|
if (result == null || result.isError()) {
|
||||||
|
throw new RuntimeException(result == null ? "盘点出库确认失败" : Convert.toStr(result.get(AjaxResult.MSG_TAG)));
|
||||||
|
}
|
||||||
|
createInventoryInboundJobIfNeeded(outboundJob, materials);
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Map<String, Object>> normalizeInventoryRequestMaterials(Map<String, Object> data, List<HashMap<String, Object>> materials) {
|
||||||
|
Object payload = data == null ? null : data.get("materials");
|
||||||
|
List<Map<String, Object>> result = new ArrayList<>();
|
||||||
|
if (payload instanceof List<?> list && !list.isEmpty()) {
|
||||||
|
for (Object item : list) {
|
||||||
|
if (item instanceof Map<?, ?>) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
Map<String, Object> material = (Map<String, Object>) item;
|
||||||
|
result.add(material);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> findInventoryRequestMaterial(List<Map<String, Object>> requestMaterials, Map<String, Object> material) {
|
||||||
|
String jobDetailId = mapString(material, "jobDetailId");
|
||||||
|
String stockDetailId = mapString(material, "stockDetailId");
|
||||||
|
String stockpdDetailId = mapString(material, "stockpdDetailId");
|
||||||
|
for (Map<String, Object> requestMaterial : requestMaterials) {
|
||||||
|
if (StringUtils.hasText(jobDetailId) && jobDetailId.equals(mapString(requestMaterial, "jobDetailId"))) {
|
||||||
|
return requestMaterial;
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(stockDetailId) && stockDetailId.equals(mapString(requestMaterial, "stockDetailId"))) {
|
||||||
|
return requestMaterial;
|
||||||
|
}
|
||||||
|
if (StringUtils.hasText(stockpdDetailId) && stockpdDetailId.equals(mapString(requestMaterial, "stockpdDetailId"))) {
|
||||||
|
return requestMaterial;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return material;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertInventoryCommitRecord(Map<String, Object> detail, Map<String, Object> material,
|
||||||
|
BigDecimal oldQuantity, BigDecimal actualQuantity) {
|
||||||
|
PdCommitRecord record = new PdCommitRecord();
|
||||||
|
record.setWarehouseId(Convert.toStr(detail.get("warehouseId")));
|
||||||
|
record.setTrayCode(Convert.toStr(detail.get("trayCode")));
|
||||||
|
record.setStockId(mapString(material, "stockId"));
|
||||||
|
record.setProductId(mapProductId(material));
|
||||||
|
record.setOldQuantity(oldQuantity.longValue());
|
||||||
|
record.setPdQuantity(actualQuantity.longValue());
|
||||||
|
record.setUserId(SecurityUtils.getUserId());
|
||||||
|
record.setDepeId(SecurityUtils.getDeptId());
|
||||||
|
record.setStockpdDetailId(mapString(material, "stockpdDetailId"));
|
||||||
|
record.setCreateTime(DateUtils.getNowDate());
|
||||||
|
pdCommitRecordMapper.insertPdCommitRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertInventoryDifferenceRecord(Map<String, Object> detail, Map<String, Object> material,
|
||||||
|
BigDecimal oldQuantity, BigDecimal actualQuantity) {
|
||||||
|
PdDifferenceRecord record = new PdDifferenceRecord();
|
||||||
|
record.setWarehouseId(Convert.toStr(detail.get("warehouseId")));
|
||||||
|
record.setWarehouseName(Convert.toStr(detail.get("warehouseName")));
|
||||||
|
record.setTrayCode(Convert.toStr(detail.get("trayCode")));
|
||||||
|
record.setProductId(mapProductId(material));
|
||||||
|
record.setProductName(mapProductName(material));
|
||||||
|
record.setOldQuantity(oldQuantity.longValue());
|
||||||
|
record.setPdQuantity(actualQuantity.longValue());
|
||||||
|
record.setUserId(SecurityUtils.getUserId());
|
||||||
|
record.setUserName(SecurityUtils.getUsername());
|
||||||
|
record.setDepeId(SecurityUtils.getDeptId());
|
||||||
|
record.setDepeName(null);
|
||||||
|
record.setStockpdDetailId(mapString(material, "stockpdDetailId"));
|
||||||
|
record.setStatus("0");
|
||||||
|
record.setRecordType(resolveDifferenceRecordType(oldQuantity, actualQuantity));
|
||||||
|
record.setCreateTime(DateUtils.getNowDate());
|
||||||
|
pdDifferenceRecordMapper.insertPdDifferenceRecord(record);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveDifferenceRecordType(BigDecimal oldQuantity, BigDecimal actualQuantity) {
|
||||||
|
if (oldQuantity.compareTo(actualQuantity) < 0) {
|
||||||
|
return "1";
|
||||||
|
}
|
||||||
|
if (actualQuantity.compareTo(BigDecimal.ZERO) == 0) {
|
||||||
|
return "3";
|
||||||
|
}
|
||||||
|
return "2";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateInventoryStockpdDetail(Map<String, Object> detail, Map<String, Object> material,
|
||||||
|
BigDecimal oldQuantity, BigDecimal actualQuantity) {
|
||||||
|
PdStockpdDetail update = new PdStockpdDetail();
|
||||||
|
update.setStockpdDetailId(mapString(material, "stockpdDetailId"));
|
||||||
|
update.setStockId(mapString(material, "stockId"));
|
||||||
|
update.setStockDetailId(mapString(material, "stockDetailId"));
|
||||||
|
update.setTrayCode(Convert.toStr(detail.get("trayCode")));
|
||||||
|
update.setWarehouseId(Convert.toStr(detail.get("warehouseId")));
|
||||||
|
update.setWarehouseName(Convert.toStr(detail.get("warehouseName")));
|
||||||
|
update.setCargoSpaceId(Convert.toStr(detail.get("locationCode")));
|
||||||
|
update.setCargoSpaceName(Convert.toStr(detail.get("locationName")));
|
||||||
|
update.setProductId(mapProductId(material));
|
||||||
|
update.setProductName(mapProductName(material));
|
||||||
|
update.setQuantity(oldQuantity.longValue());
|
||||||
|
update.setAllotNum(actualQuantity.longValue());
|
||||||
|
update.setAssignNum(actualQuantity.longValue());
|
||||||
|
pdStockpdDetailMapper.updatePdStockpdDetail(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createInventoryInboundJobIfNeeded(MydoJob outboundJob, List<HashMap<String, Object>> materials) {
|
||||||
|
if (outboundJob == null || !StringUtils.hasText(outboundJob.getTrayCode()) || !StringUtils.hasText(outboundJob.getWarehouseId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
HashMap<String, Object> exists = pdaMapper.selectInventoryInboundJobByOutboundJobId(outboundJob.getJobId());
|
||||||
|
if (exists != null && !exists.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String returnJobId = jobIdService.getId("PR");
|
||||||
|
String returnTaskNo = taskNoService.getTaskNo("2");
|
||||||
|
MydoJob returnJob = new MydoJob();
|
||||||
|
returnJob.setJobId(returnJobId);
|
||||||
|
returnJob.setTaskNo(StringUtils.hasText(returnTaskNo) ? returnTaskNo : returnJobId);
|
||||||
|
returnJob.setInOrOut(resolveInventoryInboundType(outboundJob));
|
||||||
|
returnJob.setStatus("1");
|
||||||
|
returnJob.setExecutionPhase("0");
|
||||||
|
returnJob.setTrayCode(outboundJob.getTrayCode());
|
||||||
|
returnJob.setWarehouseId(outboundJob.getWarehouseId());
|
||||||
|
returnJob.setWarehouseName(outboundJob.getWarehouseName());
|
||||||
|
returnJob.setEntranceId(outboundJob.getExitId());
|
||||||
|
returnJob.setPriority(10L);
|
||||||
|
returnJob.setHeight(BigDecimal.ZERO);
|
||||||
|
returnJob.setWeight(BigDecimal.ZERO);
|
||||||
|
copyLoginUser(returnJob);
|
||||||
|
if (StringUtils.hasText(outboundJob.getExitId())) {
|
||||||
|
BasStationPoint exitPoint = basStationPointService.selectBasStationPointByPointId(outboundJob.getExitId());
|
||||||
|
if (exitPoint != null) {
|
||||||
|
returnJob.setRoadwayId(exitPoint.getRoadwayId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mydoJobService.insertMydoJob(returnJob) <= 0) {
|
||||||
|
throw new RuntimeException("盘点入库作业生成失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
int index = 1;
|
||||||
|
for (HashMap<String, Object> material : materials) {
|
||||||
|
BigDecimal quantity = toBigDecimal(firstNotBlank(mapValue(material, "quantity"), mapValue(material, "stockQuantity")));
|
||||||
|
if (quantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
MydoJobDetail returnDetail = new MydoJobDetail();
|
||||||
|
returnDetail.setJobDetailId(returnJobId + "-" + index++);
|
||||||
|
returnDetail.setJobId(returnJobId);
|
||||||
|
returnDetail.setStockId(mapString(material, "stockId"));
|
||||||
|
returnDetail.setLotNo(mapString(material, "lotNo"));
|
||||||
|
returnDetail.setInDate(DateUtils.getTime());
|
||||||
|
returnDetail.setInOrOutId(outboundJob.getJobId());
|
||||||
|
returnDetail.setInOrOutDId(mapString(material, "stockpdDetailId"));
|
||||||
|
returnDetail.setProductId(mapProductId(material));
|
||||||
|
returnDetail.setProductName(mapProductName(material));
|
||||||
|
returnDetail.setInQuantity(quantity);
|
||||||
|
returnDetail.setStockQuantity(quantity);
|
||||||
|
returnDetail.setStockinDetailId(mapString(material, "stockDetailId"));
|
||||||
|
mydoJobDetailService.insertMydoJobDetail(returnDetail);
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiResponse<String> wcsResponse = wcsClient.sendPutawayTask(returnJob);
|
||||||
|
if (wcsResponse == null || !wcsResponse.isSuccess()) {
|
||||||
|
String message = wcsResponse == null ? "WCS接口无返回" : wcsResponse.getMessage();
|
||||||
|
throw new RuntimeException("WCS盘点回库作业下发失败:" + message);
|
||||||
|
}
|
||||||
|
markInJobDispatchedToWcs(returnJobId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long resolveInventoryInboundType(MydoJob outboundJob) {
|
||||||
|
return outboundJob.getInOrOut() != null && outboundJob.getInOrOut() == LOCATION_INVENTORY_OUT_TYPE ? 11L : 10L;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String mapProductId(Map<String, Object> material) {
|
||||||
|
return Convert.toStr(firstNotBlank(mapValue(material, "productId"), mapValue(material, "materialCode")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String mapProductName(Map<String, Object> material) {
|
||||||
|
return Convert.toStr(firstNotBlank(mapValue(material, "productName"), mapValue(material, "materialName")));
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private BigDecimal applyOutboundMaterialQuantities(Map<String, Object> data, Map<String, Object> detail) {
|
private BigDecimal applyOutboundMaterialQuantities(Map<String, Object> data, Map<String, Object> detail) {
|
||||||
Object materialPayload = data == null ? null : data.get("materials");
|
Object materialPayload = data == null ? null : data.get("materials");
|
||||||
|
|||||||
@@ -112,6 +112,88 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
where id = #{id}
|
where id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="applyApprovedDifference" parameterType="PdDifferenceRecord">
|
||||||
|
update bsd
|
||||||
|
set bsd.quantity = #{pdQuantity},
|
||||||
|
bsd.out_quantity = case
|
||||||
|
when isnull(bsd.out_quantity, 0) > #{pdQuantity} then #{pdQuantity}
|
||||||
|
else isnull(bsd.out_quantity, 0)
|
||||||
|
end,
|
||||||
|
bsd.update_time = sysdatetime()
|
||||||
|
from bas_stock_detail bsd
|
||||||
|
inner join bas_stock bs on bsd.stock_id = bs.stock_id
|
||||||
|
left join pd_stockpd_detail pdd on pdd.stockpd_detail_id = #{stockpdDetailId}
|
||||||
|
left join pd_stockpd_detail_finish pddf on pddf.stockpd_detail_id = #{stockpdDetailId}
|
||||||
|
outer apply (
|
||||||
|
select coalesce(nullif(pdd.stock_detail_id, ''), nullif(pddf.stock_detail_id, '')) as stock_detail_id
|
||||||
|
) src
|
||||||
|
where (
|
||||||
|
src.stock_detail_id is not null
|
||||||
|
and (bsd.stockin_detail_id = src.stock_detail_id or bsd.detail_id = src.stock_detail_id)
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
src.stock_detail_id is null
|
||||||
|
and bs.tray_code = #{trayCode}
|
||||||
|
and bsd.product_id = #{productId}
|
||||||
|
<if test="warehouseId != null and warehouseId != ''">
|
||||||
|
and bs.warehouse_id = #{warehouseId}
|
||||||
|
</if>
|
||||||
|
)
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="refreshApprovedDifferenceStockSummary" parameterType="PdDifferenceRecord">
|
||||||
|
update bs
|
||||||
|
set bs.quantity = isnull(bsa.quantity, 0),
|
||||||
|
bs.out_quantity = isnull(bsa.out_quantity, 0)
|
||||||
|
from bas_stock bs
|
||||||
|
left join (
|
||||||
|
select stock_id,
|
||||||
|
sum(isnull(quantity, 0)) as quantity,
|
||||||
|
sum(isnull(out_quantity, 0)) as out_quantity
|
||||||
|
from bas_stock_detail
|
||||||
|
group by stock_id
|
||||||
|
) bsa on bsa.stock_id = bs.stock_id
|
||||||
|
where bs.stock_id in (
|
||||||
|
select distinct bsd.stock_id
|
||||||
|
from bas_stock_detail bsd
|
||||||
|
inner join bas_stock xbs on bsd.stock_id = xbs.stock_id
|
||||||
|
left join pd_stockpd_detail pdd on pdd.stockpd_detail_id = #{stockpdDetailId}
|
||||||
|
left join pd_stockpd_detail_finish pddf on pddf.stockpd_detail_id = #{stockpdDetailId}
|
||||||
|
outer apply (
|
||||||
|
select coalesce(nullif(pdd.stock_detail_id, ''), nullif(pddf.stock_detail_id, '')) as stock_detail_id
|
||||||
|
) src
|
||||||
|
where (
|
||||||
|
src.stock_detail_id is not null
|
||||||
|
and (bsd.stockin_detail_id = src.stock_detail_id or bsd.detail_id = src.stock_detail_id)
|
||||||
|
)
|
||||||
|
or (
|
||||||
|
src.stock_detail_id is null
|
||||||
|
and xbs.tray_code = #{trayCode}
|
||||||
|
and bsd.product_id = #{productId}
|
||||||
|
<if test="warehouseId != null and warehouseId != ''">
|
||||||
|
and xbs.warehouse_id = #{warehouseId}
|
||||||
|
</if>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
</update>
|
||||||
|
|
||||||
|
<update id="markInboundDifferencesPendingReviewByJobId" parameterType="String">
|
||||||
|
update pd_difference_record
|
||||||
|
set status = '1'
|
||||||
|
where status = '0'
|
||||||
|
and stockpd_detail_id in (
|
||||||
|
select in_or_out_d_id
|
||||||
|
from mydo_job_detail
|
||||||
|
where job_id = #{jobId}
|
||||||
|
and in_or_out_d_id is not null
|
||||||
|
union
|
||||||
|
select in_or_out_d_id
|
||||||
|
from mydo_job_detail_finish
|
||||||
|
where job_id = #{jobId}
|
||||||
|
and in_or_out_d_id is not null
|
||||||
|
)
|
||||||
|
</update>
|
||||||
|
|
||||||
<delete id="deletePdDifferenceRecordById" parameterType="Long">
|
<delete id="deletePdDifferenceRecordById" parameterType="Long">
|
||||||
delete from pd_difference_record where id = #{id}
|
delete from pd_difference_record where id = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
@@ -122,4 +204,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
#{id}
|
#{id}
|
||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<result property="stockpdDetailId" column="stockpd_detail_id" />
|
<result property="stockpdDetailId" column="stockpd_detail_id" />
|
||||||
<result property="stockpdId" column="stockpd_id" />
|
<result property="stockpdId" column="stockpd_id" />
|
||||||
<result property="trayCode" column="tray_code" />
|
<result property="trayCode" column="tray_code" />
|
||||||
|
<result property="stockId" column="stock_id" />
|
||||||
|
<result property="stockDetailId" column="stock_detail_id" />
|
||||||
|
<result property="cargoSpaceId" column="cargo_space_id" />
|
||||||
|
<result property="cargoSpaceName" column="cargo_space_name" />
|
||||||
|
<result property="warehouseId" column="warehouse_id" />
|
||||||
|
<result property="warehouseName" column="warehouse_name" />
|
||||||
<result property="productId" column="product_id" />
|
<result property="productId" column="product_id" />
|
||||||
<result property="productName" column="product_name" />
|
<result property="productName" column="product_name" />
|
||||||
<result property="quantity" column="quantity" />
|
<result property="quantity" column="quantity" />
|
||||||
@@ -17,12 +23,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<sql id="selectPdStockpdDetailVo">
|
<sql id="selectPdStockpdDetailVo">
|
||||||
select stockpd_detail_id, stockpd_id, tray_code, product_id, product_name, quantity, allot_num, assign_num, remark from pd_stockpd_detail
|
select stockpd_detail_id, stockpd_id, tray_code, stock_id, stock_detail_id, cargo_space_id, cargo_space_name,
|
||||||
|
warehouse_id, warehouse_name, product_id, product_name, quantity, allot_num, assign_num, remark
|
||||||
|
from pd_stockpd_detail
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="selectPdStockpdDetailFinishVo">
|
<sql id="selectPdStockpdDetailFinishVo">
|
||||||
select stockpd_detail_id,
|
select stockpd_detail_id,
|
||||||
stockpd_id,
|
stockpd_id,
|
||||||
tray_code,
|
tray_code,
|
||||||
|
stock_id,
|
||||||
|
stock_detail_id,
|
||||||
|
cargo_space_id,
|
||||||
|
cargo_space_name,
|
||||||
|
warehouse_id,
|
||||||
|
warehouse_name,
|
||||||
product_id,
|
product_id,
|
||||||
product_name,
|
product_name,
|
||||||
quantity,
|
quantity,
|
||||||
@@ -37,6 +51,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<where>
|
<where>
|
||||||
<if test="stockpdId != null and stockpdId != ''"> and stockpd_id = #{stockpdId}</if>
|
<if test="stockpdId != null and stockpdId != ''"> and stockpd_id = #{stockpdId}</if>
|
||||||
<if test="trayCode != null and trayCode != ''"> and tray_code = #{trayCode}</if>
|
<if test="trayCode != null and trayCode != ''"> and tray_code = #{trayCode}</if>
|
||||||
|
<if test="stockId != null and stockId != ''"> and stock_id = #{stockId}</if>
|
||||||
|
<if test="stockDetailId != null and stockDetailId != ''"> and stock_detail_id = #{stockDetailId}</if>
|
||||||
|
<if test="cargoSpaceId != null and cargoSpaceId != ''"> and cargo_space_id = #{cargoSpaceId}</if>
|
||||||
|
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
|
||||||
<if test="productId != null and productId != ''"> and product_id = #{productId}</if>
|
<if test="productId != null and productId != ''"> and product_id = #{productId}</if>
|
||||||
<if test="productName != null and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
|
<if test="productName != null and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
|
||||||
<if test="quantity != null "> and quantity = #{quantity}</if>
|
<if test="quantity != null "> and quantity = #{quantity}</if>
|
||||||
@@ -54,6 +72,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<where>
|
<where>
|
||||||
<if test="stockpdId != null and stockpdId != ''"> and stockpd_id = #{stockpdId}</if>
|
<if test="stockpdId != null and stockpdId != ''"> and stockpd_id = #{stockpdId}</if>
|
||||||
<if test="trayCode != null and trayCode != ''"> and tray_code = #{trayCode}</if>
|
<if test="trayCode != null and trayCode != ''"> and tray_code = #{trayCode}</if>
|
||||||
|
<if test="stockId != null and stockId != ''"> and stock_id = #{stockId}</if>
|
||||||
|
<if test="stockDetailId != null and stockDetailId != ''"> and stock_detail_id = #{stockDetailId}</if>
|
||||||
|
<if test="cargoSpaceId != null and cargoSpaceId != ''"> and cargo_space_id = #{cargoSpaceId}</if>
|
||||||
|
<if test="warehouseId != null and warehouseId != ''"> and warehouse_id = #{warehouseId}</if>
|
||||||
<if test="productId != null and productId != ''"> and product_id = #{productId}</if>
|
<if test="productId != null and productId != ''"> and product_id = #{productId}</if>
|
||||||
<if test="productName != null and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
|
<if test="productName != null and productName != ''"> and product_name like concat('%', #{productName}, '%')</if>
|
||||||
<if test="quantity != null "> and quantity = #{quantity}</if>
|
<if test="quantity != null "> and quantity = #{quantity}</if>
|
||||||
@@ -68,6 +90,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="stockpdDetailId != null">stockpd_detail_id,</if>
|
<if test="stockpdDetailId != null">stockpd_detail_id,</if>
|
||||||
<if test="stockpdId != null and stockpdId != ''">stockpd_id,</if>
|
<if test="stockpdId != null and stockpdId != ''">stockpd_id,</if>
|
||||||
<if test="trayCode != null">tray_code,</if>
|
<if test="trayCode != null">tray_code,</if>
|
||||||
|
<if test="stockId != null">stock_id,</if>
|
||||||
|
<if test="stockDetailId != null">stock_detail_id,</if>
|
||||||
|
<if test="cargoSpaceId != null">cargo_space_id,</if>
|
||||||
|
<if test="cargoSpaceName != null">cargo_space_name,</if>
|
||||||
|
<if test="warehouseId != null">warehouse_id,</if>
|
||||||
|
<if test="warehouseName != null">warehouse_name,</if>
|
||||||
<if test="productId != null and productId != ''">product_id,</if>
|
<if test="productId != null and productId != ''">product_id,</if>
|
||||||
<if test="productName != null">product_name,</if>
|
<if test="productName != null">product_name,</if>
|
||||||
<if test="quantity != null">quantity,</if>
|
<if test="quantity != null">quantity,</if>
|
||||||
@@ -79,6 +107,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="stockpdDetailId != null">#{stockpdDetailId},</if>
|
<if test="stockpdDetailId != null">#{stockpdDetailId},</if>
|
||||||
<if test="stockpdId != null and stockpdId != ''">#{stockpdId},</if>
|
<if test="stockpdId != null and stockpdId != ''">#{stockpdId},</if>
|
||||||
<if test="trayCode != null">#{trayCode},</if>
|
<if test="trayCode != null">#{trayCode},</if>
|
||||||
|
<if test="stockId != null">#{stockId},</if>
|
||||||
|
<if test="stockDetailId != null">#{stockDetailId},</if>
|
||||||
|
<if test="cargoSpaceId != null">#{cargoSpaceId},</if>
|
||||||
|
<if test="cargoSpaceName != null">#{cargoSpaceName},</if>
|
||||||
|
<if test="warehouseId != null">#{warehouseId},</if>
|
||||||
|
<if test="warehouseName != null">#{warehouseName},</if>
|
||||||
<if test="productId != null and productId != ''">#{productId},</if>
|
<if test="productId != null and productId != ''">#{productId},</if>
|
||||||
<if test="productName != null">#{productName},</if>
|
<if test="productName != null">#{productName},</if>
|
||||||
<if test="quantity != null">#{quantity},</if>
|
<if test="quantity != null">#{quantity},</if>
|
||||||
@@ -93,6 +127,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<trim prefix="SET" suffixOverrides=",">
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
<if test="stockpdId != null and stockpdId != ''">stockpd_id = #{stockpdId},</if>
|
<if test="stockpdId != null and stockpdId != ''">stockpd_id = #{stockpdId},</if>
|
||||||
<if test="trayCode != null">tray_code = #{trayCode},</if>
|
<if test="trayCode != null">tray_code = #{trayCode},</if>
|
||||||
|
<if test="stockId != null">stock_id = #{stockId},</if>
|
||||||
|
<if test="stockDetailId != null">stock_detail_id = #{stockDetailId},</if>
|
||||||
|
<if test="cargoSpaceId != null">cargo_space_id = #{cargoSpaceId},</if>
|
||||||
|
<if test="cargoSpaceName != null">cargo_space_name = #{cargoSpaceName},</if>
|
||||||
|
<if test="warehouseId != null">warehouse_id = #{warehouseId},</if>
|
||||||
|
<if test="warehouseName != null">warehouse_name = #{warehouseName},</if>
|
||||||
<if test="productId != null and productId != ''">product_id = #{productId},</if>
|
<if test="productId != null and productId != ''">product_id = #{productId},</if>
|
||||||
<if test="productName != null">product_name = #{productName},</if>
|
<if test="productName != null">product_name = #{productName},</if>
|
||||||
<if test="quantity != null">quantity = #{quantity},</if>
|
<if test="quantity != null">quantity = #{quantity},</if>
|
||||||
@@ -113,4 +153,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
#{stockpdDetailId}
|
#{stockpdDetailId}
|
||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -120,12 +120,48 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
from mydo_job j
|
from mydo_job j
|
||||||
inner join mydo_job_detail jd on j.job_id = jd.job_id
|
inner join mydo_job_detail jd on j.job_id = jd.job_id
|
||||||
where j.in_or_out >= 20
|
where j.in_or_out >= 20
|
||||||
|
and j.in_or_out not in (30, 31)
|
||||||
and j.status in ('1', '2', '3')
|
and j.status in ('1', '2', '3')
|
||||||
and (#{taskNo} is null or #{taskNo} = '' or j.task_no = #{taskNo})
|
and (#{taskNo} is null or #{taskNo} = '' or j.task_no = #{taskNo})
|
||||||
group by j.job_id, j.task_no, j.exit_id, j.create_time, j.status, j.execution_phase
|
group by j.job_id, j.task_no, j.exit_id, j.create_time, j.status, j.execution_phase
|
||||||
order by j.create_time desc
|
order by j.create_time desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="inventoryTaskList" parameterType="java.util.Map" resultType="java.util.HashMap">
|
||||||
|
select j.job_id as jobId,
|
||||||
|
j.task_no as taskNo,
|
||||||
|
'inventory' as type,
|
||||||
|
case when j.in_or_out = 31 then '货位盘点' else '物料盘点' end as typeName,
|
||||||
|
'inventory' as typeClass,
|
||||||
|
max(jd.product_id) as materialCode,
|
||||||
|
max(jd.product_name) as materialName,
|
||||||
|
sum(isnull(jd.out_quantity, 0)) as quantity,
|
||||||
|
isnull(j.exit_id, '') as portName,
|
||||||
|
j.tray_code as trayCode,
|
||||||
|
convert(varchar(19), j.create_time, 120) as createTime,
|
||||||
|
j.status as status,
|
||||||
|
j.execution_phase as executionPhase,
|
||||||
|
case
|
||||||
|
when j.execution_phase = '5' then '待扫码盘点'
|
||||||
|
when j.status = '1' then '未下发'
|
||||||
|
when j.status = '2' then '待执行'
|
||||||
|
when j.status = '3' then 'WCS执行中'
|
||||||
|
else '待盘点'
|
||||||
|
end as statusName,
|
||||||
|
case
|
||||||
|
when j.execution_phase = '5' then 'pending'
|
||||||
|
when j.status = '3' then 'processing'
|
||||||
|
else 'pending'
|
||||||
|
end as statusClass
|
||||||
|
from mydo_job j
|
||||||
|
inner join mydo_job_detail jd on j.job_id = jd.job_id
|
||||||
|
where j.in_or_out in (30, 31)
|
||||||
|
and j.status in ('1', '2', '3')
|
||||||
|
and (#{taskNo} is null or #{taskNo} = '' or j.task_no = #{taskNo})
|
||||||
|
group by j.job_id, j.task_no, j.in_or_out, j.exit_id, j.tray_code, j.create_time, j.status, j.execution_phase
|
||||||
|
order by j.create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectOutboundDetail" parameterType="java.util.Map" resultType="java.util.HashMap">
|
<select id="selectOutboundDetail" parameterType="java.util.Map" resultType="java.util.HashMap">
|
||||||
select top 1 j.job_id as jobId,
|
select top 1 j.job_id as jobId,
|
||||||
j.task_no as taskNo,
|
j.task_no as taskNo,
|
||||||
@@ -142,6 +178,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
from mydo_job j
|
from mydo_job j
|
||||||
inner join mydo_job_detail jd on j.job_id = jd.job_id
|
inner join mydo_job_detail jd on j.job_id = jd.job_id
|
||||||
where j.in_or_out >= 20
|
where j.in_or_out >= 20
|
||||||
|
and j.in_or_out not in (30, 31)
|
||||||
and j.status in ('1', '2', '3')
|
and j.status in ('1', '2', '3')
|
||||||
and (#{taskNo} is null or #{taskNo} = '' or j.task_no = #{taskNo})
|
and (#{taskNo} is null or #{taskNo} = '' or j.task_no = #{taskNo})
|
||||||
and (#{barcode} is null or #{barcode} = '' or j.tray_code = #{barcode})
|
and (#{barcode} is null or #{barcode} = '' or j.tray_code = #{barcode})
|
||||||
@@ -150,6 +187,31 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
order by j.create_time desc
|
order by j.create_time desc
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectInventoryDetail" parameterType="java.util.Map" resultType="java.util.HashMap">
|
||||||
|
select top 1 j.job_id as jobId,
|
||||||
|
j.task_no as taskNo,
|
||||||
|
j.tray_code as trayCode,
|
||||||
|
j.cargo_space_id as locationCode,
|
||||||
|
j.cargo_space_name as locationName,
|
||||||
|
j.warehouse_id as warehouseId,
|
||||||
|
j.warehouse_name as warehouseName,
|
||||||
|
j.execution_phase as executionPhase,
|
||||||
|
j.in_or_out as inventoryType,
|
||||||
|
isnull(j.exit_id, '') as portName,
|
||||||
|
sum(isnull(jd.out_quantity, 0)) as quantity,
|
||||||
|
count(1) as materialCount,
|
||||||
|
'' as spec
|
||||||
|
from mydo_job j
|
||||||
|
inner join mydo_job_detail jd on j.job_id = jd.job_id
|
||||||
|
where j.in_or_out in (30, 31)
|
||||||
|
and j.status in ('1', '2', '3')
|
||||||
|
and (#{taskNo} is null or #{taskNo} = '' or j.task_no = #{taskNo})
|
||||||
|
and (#{barcode} is null or #{barcode} = '' or j.tray_code = #{barcode})
|
||||||
|
group by j.job_id, j.task_no, j.tray_code, j.cargo_space_id, j.cargo_space_name,
|
||||||
|
j.warehouse_id, j.warehouse_name, j.execution_phase, j.in_or_out, j.exit_id, j.create_time
|
||||||
|
order by j.create_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectOutboundTrayMaterials" parameterType="java.util.Map" resultType="java.util.HashMap">
|
<select id="selectOutboundTrayMaterials" parameterType="java.util.Map" resultType="java.util.HashMap">
|
||||||
select jd.job_detail_id as jobDetailId,
|
select jd.job_detail_id as jobDetailId,
|
||||||
jd.stock_id as stockId,
|
jd.stock_id as stockId,
|
||||||
@@ -165,6 +227,45 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
order by jd.job_detail_id
|
order by jd.job_detail_id
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectInventoryTrayMaterials" parameterType="java.util.Map" resultType="java.util.HashMap">
|
||||||
|
select jd.job_detail_id as jobDetailId,
|
||||||
|
jd.stock_id as stockId,
|
||||||
|
jd.stockin_detail_id as stockDetailId,
|
||||||
|
jd.in_or_out_d_id as stockpdDetailId,
|
||||||
|
jd.product_id as materialCode,
|
||||||
|
jd.product_name as materialName,
|
||||||
|
jd.lot_no as lotNo,
|
||||||
|
jd.stock_quantity as stockQuantity,
|
||||||
|
jd.out_quantity as quantity
|
||||||
|
from mydo_job_detail jd
|
||||||
|
where jd.job_id = #{jobId}
|
||||||
|
order by jd.job_detail_id
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectInventoryInboundJobByOutboundJobId" parameterType="String" resultType="java.util.HashMap">
|
||||||
|
select top 1 jobId, taskNo, status
|
||||||
|
from (
|
||||||
|
select j.job_id as jobId,
|
||||||
|
j.task_no as taskNo,
|
||||||
|
j.status as status,
|
||||||
|
j.create_time as createTime
|
||||||
|
from mydo_job j
|
||||||
|
inner join mydo_job_detail jd on j.job_id = jd.job_id
|
||||||
|
where j.in_or_out in (10, 11)
|
||||||
|
and jd.in_or_out_id = #{outboundJobId}
|
||||||
|
union all
|
||||||
|
select jf.job_id as jobId,
|
||||||
|
jf.task_no as taskNo,
|
||||||
|
jf.status as status,
|
||||||
|
jf.create_time as createTime
|
||||||
|
from mydo_job_finish jf
|
||||||
|
inner join mydo_job_detail_finish jdf on jf.job_id = jdf.job_id
|
||||||
|
where jf.in_or_out in (10, 11)
|
||||||
|
and jdf.in_or_out_id = #{outboundJobId}
|
||||||
|
) x
|
||||||
|
order by createTime desc
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="selectResidualTrayMaterials" parameterType="java.util.Map" resultType="java.util.HashMap">
|
<select id="selectResidualTrayMaterials" parameterType="java.util.Map" resultType="java.util.HashMap">
|
||||||
select bsd.detail_id as stockDetailId,
|
select bsd.detail_id as stockDetailId,
|
||||||
bsd.stock_id as stockId,
|
bsd.stock_id as stockId,
|
||||||
@@ -301,6 +402,16 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
and isnull(quantity, 0) - isnull(out_quantity, 0) >= #{quantity}
|
and isnull(quantity, 0) - isnull(out_quantity, 0) >= #{quantity}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="reserveInventoryStockDetail" parameterType="java.util.Map">
|
||||||
|
update bas_stock_detail
|
||||||
|
set out_quantity = isnull(out_quantity, 0) + #{quantity},
|
||||||
|
job_detail_id = #{jobDetailId},
|
||||||
|
update_time = sysdatetime()
|
||||||
|
where detail_id = #{stockDetailId}
|
||||||
|
and stock_id = #{stockId}
|
||||||
|
and isnull(quantity, 0) - isnull(out_quantity, 0) >= #{quantity}
|
||||||
|
</update>
|
||||||
|
|
||||||
<update id="lockEmptyTrayCargoSpace" parameterType="java.util.Map">
|
<update id="lockEmptyTrayCargoSpace" parameterType="java.util.Map">
|
||||||
update bcs
|
update bcs
|
||||||
set status = '4',
|
set status = '4',
|
||||||
@@ -310,4 +421,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
where bs.stock_id = #{stockId}
|
where bs.stock_id = #{stockId}
|
||||||
and bs.cargo_space_id = #{cargoSpaceId}
|
and bs.cargo_space_id = #{cargoSpaceId}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="lockInventoryOutboundCargoSpace" parameterType="java.util.Map">
|
||||||
|
update bcs
|
||||||
|
set status = '4',
|
||||||
|
tray_code = bs.tray_code
|
||||||
|
from bas_cargo_space bcs
|
||||||
|
inner join bas_stock bs on bcs.cargo_space_id = bs.cargo_space_id
|
||||||
|
where bs.stock_id = #{stockId}
|
||||||
|
and bs.cargo_space_id = #{cargoSpaceId}
|
||||||
|
</update>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import com.ruoyi.in.jobdetail.mapper.MydoJobDetailMapper;
|
|||||||
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
||||||
import com.ruoyi.out.stockout.mapper.OutStockoutMapper;
|
import com.ruoyi.out.stockout.mapper.OutStockoutMapper;
|
||||||
import com.ruoyi.out.stockoutdetail.mapper.OutStockoutDetailMapper;
|
import com.ruoyi.out.stockoutdetail.mapper.OutStockoutDetailMapper;
|
||||||
|
import com.ruoyi.pd.diff.mapper.PdDifferenceRecordMapper;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@@ -71,6 +72,9 @@ class MydoJobServiceImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private WcsClient wcsClient;
|
private WcsClient wcsClient;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdDifferenceRecordMapper pdDifferenceRecordMapper;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private MydoJobServiceImpl service;
|
private MydoJobServiceImpl service;
|
||||||
|
|
||||||
@@ -225,6 +229,26 @@ class MydoJobServiceImplTest {
|
|||||||
verify(mydoJobMapper, never()).completeJob(any(java.util.HashMap.class));
|
verify(mydoJobMapper, never()).completeJob(any(java.util.HashMap.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void completeInventoryInboundFromWcsMarksDifferencesPendingReviewAfterProcedureSucceeds() {
|
||||||
|
MydoJob job = new MydoJob();
|
||||||
|
job.setJobId("PR001");
|
||||||
|
job.setInOrOut(10L);
|
||||||
|
when(mydoJobMapper.selectMydoJobByJobId("PR001")).thenReturn(job);
|
||||||
|
when(mydoJobMapper.selectStockinIdsByJobId("PR001")).thenReturn(Collections.emptyList());
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
java.util.HashMap<String, Object> map = invocation.getArgument(0);
|
||||||
|
map.put("v_result", "1");
|
||||||
|
return null;
|
||||||
|
}).when(mydoJobMapper).completeJob(any(java.util.HashMap.class));
|
||||||
|
|
||||||
|
AjaxResult result = service.completeInJobFromWcs("PR001");
|
||||||
|
|
||||||
|
assertThat(result.isSuccess()).isTrue();
|
||||||
|
verify(pdDifferenceRecordMapper).markInboundDifferencesPendingReviewByJobId("PR001");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void completeOutJobFromWcsRejectsInboundJobType() {
|
void completeOutJobFromWcsRejectsInboundJobType() {
|
||||||
MydoJob job = new MydoJob();
|
MydoJob job = new MydoJob();
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
package com.ruoyi.pd.diff.service.impl;
|
||||||
|
|
||||||
|
import com.ruoyi.pd.diff.domain.PdDifferenceRecord;
|
||||||
|
import com.ruoyi.pd.diff.mapper.PdDifferenceRecordMapper;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class PdDifferenceRecordServiceImplTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdDifferenceRecordMapper pdDifferenceRecordMapper;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private PdDifferenceRecordServiceImpl service;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void approvePendingDifferenceAppliesStockQuantityAndMarksApproved() {
|
||||||
|
PdDifferenceRecord record = new PdDifferenceRecord();
|
||||||
|
record.setId(1L);
|
||||||
|
record.setStatus("1");
|
||||||
|
record.setRecordType("2");
|
||||||
|
record.setStockpdDetailId("PDD001-1");
|
||||||
|
record.setTrayCode("A001");
|
||||||
|
record.setProductId("MAT001");
|
||||||
|
record.setOldQuantity(5L);
|
||||||
|
record.setPdQuantity(4L);
|
||||||
|
when(pdDifferenceRecordMapper.selectPdDifferenceRecordById(1L)).thenReturn(record);
|
||||||
|
when(pdDifferenceRecordMapper.applyApprovedDifference(record)).thenReturn(1);
|
||||||
|
when(pdDifferenceRecordMapper.refreshApprovedDifferenceStockSummary(record)).thenReturn(1);
|
||||||
|
when(pdDifferenceRecordMapper.updatePdDifferenceRecord(record)).thenReturn(1);
|
||||||
|
|
||||||
|
int rows = service.approvePdDifferenceRecord(1L);
|
||||||
|
|
||||||
|
assertThat(rows).isEqualTo(1);
|
||||||
|
verify(pdDifferenceRecordMapper).applyApprovedDifference(record);
|
||||||
|
verify(pdDifferenceRecordMapper).refreshApprovedDifferenceStockSummary(record);
|
||||||
|
ArgumentCaptor<PdDifferenceRecord> updateCaptor = ArgumentCaptor.forClass(PdDifferenceRecord.class);
|
||||||
|
verify(pdDifferenceRecordMapper).updatePdDifferenceRecord(updateCaptor.capture());
|
||||||
|
assertThat(updateCaptor.getValue().getStatus()).isEqualTo("2");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void rejectPendingDifferenceLeavesStockUntouchedAndMarksRejected() {
|
||||||
|
PdDifferenceRecord record = new PdDifferenceRecord();
|
||||||
|
record.setId(2L);
|
||||||
|
record.setStatus("1");
|
||||||
|
when(pdDifferenceRecordMapper.selectPdDifferenceRecordById(2L)).thenReturn(record);
|
||||||
|
when(pdDifferenceRecordMapper.updatePdDifferenceRecord(record)).thenReturn(1);
|
||||||
|
|
||||||
|
int rows = service.rejectPdDifferenceRecord(2L);
|
||||||
|
|
||||||
|
assertThat(rows).isEqualTo(1);
|
||||||
|
ArgumentCaptor<PdDifferenceRecord> updateCaptor = ArgumentCaptor.forClass(PdDifferenceRecord.class);
|
||||||
|
verify(pdDifferenceRecordMapper).updatePdDifferenceRecord(updateCaptor.capture());
|
||||||
|
assertThat(updateCaptor.getValue().getStatus()).isEqualTo("3");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
package com.ruoyi.pd.stockpd.service.impl;
|
||||||
|
|
||||||
|
import com.ruoyi.bas.id.job.service.JobIdService;
|
||||||
|
import com.ruoyi.bas.id.taskno.service.TaskNoService;
|
||||||
|
import com.ruoyi.bas.stock.domain.BasStockDetail;
|
||||||
|
import com.ruoyi.bas.stock.mapper.BasStockDetailMapper;
|
||||||
|
import com.ruoyi.bas.stationpoint.domain.BasStationPoint;
|
||||||
|
import com.ruoyi.bas.stationpoint.service.IBasStationPointService;
|
||||||
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.in.job.domain.MydoJob;
|
||||||
|
import com.ruoyi.in.job.service.IMydoJobService;
|
||||||
|
import com.ruoyi.in.jobdetail.domain.MydoJobDetail;
|
||||||
|
import com.ruoyi.in.jobdetail.service.IMydoJobDetailService;
|
||||||
|
import com.ruoyi.pd.stockpd.domain.PdStockpd;
|
||||||
|
import com.ruoyi.pd.stockpd.mapper.PdStockpdMapper;
|
||||||
|
import com.ruoyi.pd.stockpddetail.domain.PdStockpdDetail;
|
||||||
|
import com.ruoyi.pd.stockpddetail.mapper.PdStockpdDetailMapper;
|
||||||
|
import com.ruoyi.pda.mapper.PdaMapper;
|
||||||
|
import com.ruoyi.system.mapper.SysDeptMapper;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InjectMocks;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class PdStockpdServiceImplTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdStockpdMapper pdStockpdMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdStockpdDetailMapper pdStockpdDetailMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SysDeptMapper sysDeptMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private JobIdService jobIdService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TaskNoService taskNoService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private BasStockDetailMapper basStockDetailMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IBasStationPointService basStationPointService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IMydoJobService mydoJobService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private IMydoJobDetailService mydoJobDetailService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdaMapper pdaMapper;
|
||||||
|
|
||||||
|
@InjectMocks
|
||||||
|
private PdStockpdServiceImpl service;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void autoAssignCreatesInventoryOutboundJobFromStockDetailAndPushesWcs() {
|
||||||
|
PdStockpd stockpd = new PdStockpd();
|
||||||
|
stockpd.setStockpdId("PDD001");
|
||||||
|
stockpd.setPdType("1");
|
||||||
|
stockpd.setStatus("2");
|
||||||
|
stockpd.setWarehouseId("WH01");
|
||||||
|
stockpd.setWarehouseName("一号仓");
|
||||||
|
when(pdStockpdMapper.selectPdStockpdByStockpdId("PDD001")).thenReturn(stockpd);
|
||||||
|
|
||||||
|
PdStockpdDetail detail = new PdStockpdDetail();
|
||||||
|
detail.setStockpdDetailId("PDD001-1");
|
||||||
|
detail.setStockpdId("PDD001");
|
||||||
|
detail.setStockId("KC001");
|
||||||
|
detail.setStockDetailId("SD001");
|
||||||
|
detail.setTrayCode("A001");
|
||||||
|
detail.setProductId("MAT001");
|
||||||
|
detail.setProductName("物料1");
|
||||||
|
detail.setQuantity(5L);
|
||||||
|
when(pdStockpdDetailMapper.selectPdStockpdDetailList(any(PdStockpdDetail.class))).thenReturn(List.of(detail));
|
||||||
|
|
||||||
|
BasStockDetail stockDetail = new BasStockDetail();
|
||||||
|
stockDetail.setDetailId("SD001");
|
||||||
|
stockDetail.setStockId("KC001");
|
||||||
|
stockDetail.setTrayCode("A001");
|
||||||
|
stockDetail.setWarehouseId("WH01");
|
||||||
|
stockDetail.setWarehouseName("一号仓");
|
||||||
|
stockDetail.setCargoSpaceId("CS001");
|
||||||
|
stockDetail.setCargoSpaceName("货位1");
|
||||||
|
stockDetail.setLotNo("LOT1");
|
||||||
|
stockDetail.setProductId("MAT001");
|
||||||
|
stockDetail.setProductName("物料1");
|
||||||
|
stockDetail.setQuantity(new BigDecimal("5"));
|
||||||
|
stockDetail.setAvailableQuantity(new BigDecimal("5"));
|
||||||
|
when(basStockDetailMapper.selectBasStockDetailByDetailId("SD001")).thenReturn(stockDetail);
|
||||||
|
|
||||||
|
BasStationPoint exitPoint = new BasStationPoint();
|
||||||
|
exitPoint.setPointId("OUT01");
|
||||||
|
exitPoint.setWarehouseId("WH01");
|
||||||
|
exitPoint.setRoadwayId("R01");
|
||||||
|
exitPoint.setPointType("2");
|
||||||
|
exitPoint.setStatus("0");
|
||||||
|
when(basStationPointService.selectBasStationPointList(any(BasStationPoint.class))).thenReturn(List.of(exitPoint));
|
||||||
|
when(jobIdService.getId("PC")).thenReturn("PC001");
|
||||||
|
when(taskNoService.getTaskNo("22")).thenReturn("40001");
|
||||||
|
when(mydoJobService.insertMydoJob(any(MydoJob.class))).thenReturn(1);
|
||||||
|
when(mydoJobDetailService.insertMydoJobDetail(any(MydoJobDetail.class))).thenReturn(1);
|
||||||
|
when(pdaMapper.reserveInventoryStockDetail(any(HashMap.class))).thenReturn(1);
|
||||||
|
when(pdaMapper.lockInventoryOutboundCargoSpace(any(HashMap.class))).thenReturn(1);
|
||||||
|
when(mydoJobService.pushOutJobToWcs("PC001")).thenReturn(AjaxResult.success("WCS出库作业下发成功:OK"));
|
||||||
|
when(pdStockpdMapper.updatePdStockpd(any(PdStockpd.class))).thenReturn(1);
|
||||||
|
when(pdStockpdDetailMapper.updatePdStockpdDetail(any(PdStockpdDetail.class))).thenReturn(1);
|
||||||
|
|
||||||
|
AjaxResult result = service.autoAssignPdStockpd("PDD001");
|
||||||
|
|
||||||
|
assertThat(result.isSuccess()).isTrue();
|
||||||
|
ArgumentCaptor<MydoJob> jobCaptor = ArgumentCaptor.forClass(MydoJob.class);
|
||||||
|
verify(mydoJobService).insertMydoJob(jobCaptor.capture());
|
||||||
|
MydoJob job = jobCaptor.getValue();
|
||||||
|
assertThat(job.getJobId()).isEqualTo("PC001");
|
||||||
|
assertThat(job.getTaskNo()).isEqualTo("40001");
|
||||||
|
assertThat(job.getInOrOut()).isEqualTo(30L);
|
||||||
|
assertThat(job.getTrayCode()).isEqualTo("A001");
|
||||||
|
assertThat(job.getWarehouseId()).isEqualTo("WH01");
|
||||||
|
assertThat(job.getCargoSpaceId()).isEqualTo("CS001");
|
||||||
|
assertThat(job.getExitId()).isEqualTo("OUT01");
|
||||||
|
|
||||||
|
ArgumentCaptor<MydoJobDetail> detailCaptor = ArgumentCaptor.forClass(MydoJobDetail.class);
|
||||||
|
verify(mydoJobDetailService).insertMydoJobDetail(detailCaptor.capture());
|
||||||
|
MydoJobDetail jobDetail = detailCaptor.getValue();
|
||||||
|
assertThat(jobDetail.getJobDetailId()).isEqualTo("PC001-1");
|
||||||
|
assertThat(jobDetail.getStockId()).isEqualTo("KC001");
|
||||||
|
assertThat(jobDetail.getStockinDetailId()).isEqualTo("SD001");
|
||||||
|
assertThat(jobDetail.getInOrOutId()).isEqualTo("PDD001");
|
||||||
|
assertThat(jobDetail.getInOrOutDId()).isEqualTo("PDD001-1");
|
||||||
|
assertThat(jobDetail.getOutQuantity()).isEqualByComparingTo("5");
|
||||||
|
|
||||||
|
ArgumentCaptor<HashMap> reserveCaptor = ArgumentCaptor.forClass(HashMap.class);
|
||||||
|
verify(pdaMapper).reserveInventoryStockDetail(reserveCaptor.capture());
|
||||||
|
assertThat(reserveCaptor.getValue())
|
||||||
|
.containsEntry("stockDetailId", "SD001")
|
||||||
|
.containsEntry("stockId", "KC001")
|
||||||
|
.containsEntry("jobDetailId", "PC001-1")
|
||||||
|
.containsEntry("quantity", new BigDecimal("5"));
|
||||||
|
|
||||||
|
verify(mydoJobService).pushOutJobToWcs("PC001");
|
||||||
|
verify(pdStockpdMapper).updatePdStockpd(any(PdStockpd.class));
|
||||||
|
verify(pdStockpdDetailMapper).updatePdStockpdDetail(any(PdStockpdDetail.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -86,10 +86,26 @@ class PdaMapperSqlTest {
|
|||||||
.contains("j.execution_phase as executionPhase")
|
.contains("j.execution_phase as executionPhase")
|
||||||
.contains("when j.execution_phase = '5' then '待扫码确认'")
|
.contains("when j.execution_phase = '5' then '待扫码确认'")
|
||||||
.contains("and j.status in ('1', '2', '3')")
|
.contains("and j.status in ('1', '2', '3')")
|
||||||
|
.contains("and j.in_or_out not in (30, 31)")
|
||||||
.contains("group by j.job_id, j.task_no, j.exit_id, j.create_time, j.status, j.execution_phase");
|
.contains("group by j.job_id, j.task_no, j.exit_id, j.create_time, j.status, j.execution_phase");
|
||||||
assertThat(detailSql)
|
assertThat(detailSql)
|
||||||
.contains("j.execution_phase as executionPhase")
|
.contains("j.execution_phase as executionPhase")
|
||||||
.contains("and j.status in ('1', '2', '3')");
|
.contains("and j.status in ('1', '2', '3')")
|
||||||
|
.contains("and j.in_or_out not in (30, 31)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void inventoryQueriesUseDedicatedInventoryJobTypes() throws Exception {
|
||||||
|
String xml = Files.readString(resolveMapperXml());
|
||||||
|
String detailSql = section(xml, "<select id=\"selectInventoryDetail\"", "</select>");
|
||||||
|
String materialsSql = section(xml, "<select id=\"selectInventoryTrayMaterials\"", "</select>");
|
||||||
|
|
||||||
|
assertThat(detailSql)
|
||||||
|
.contains("j.in_or_out in (30, 31)")
|
||||||
|
.contains("j.execution_phase as executionPhase");
|
||||||
|
assertThat(materialsSql)
|
||||||
|
.contains("jd.in_or_out_d_id as stockpdDetailId")
|
||||||
|
.contains("jd.stockin_detail_id as stockDetailId");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Path resolveMapperXml() {
|
private Path resolveMapperXml() {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ import com.ruoyi.in.jobdetail.domain.MydoJobDetail;
|
|||||||
import com.ruoyi.in.jobdetail.service.IMydoJobDetailService;
|
import com.ruoyi.in.jobdetail.service.IMydoJobDetailService;
|
||||||
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
import com.ruoyi.in.stockin.mapper.InStockinMapper;
|
||||||
import com.ruoyi.in.sotckindetail.mapper.InStockinDetailMapper;
|
import com.ruoyi.in.sotckindetail.mapper.InStockinDetailMapper;
|
||||||
|
import com.ruoyi.pd.commit.mapper.PdCommitRecordMapper;
|
||||||
|
import com.ruoyi.pd.diff.mapper.PdDifferenceRecordMapper;
|
||||||
|
import com.ruoyi.pd.stockpddetail.mapper.PdStockpdDetailMapper;
|
||||||
import com.ruoyi.pda.domain.AddInJobRequest;
|
import com.ruoyi.pda.domain.AddInJobRequest;
|
||||||
import com.ruoyi.pda.domain.EmptyTrayOutboundRequest;
|
import com.ruoyi.pda.domain.EmptyTrayOutboundRequest;
|
||||||
import com.ruoyi.pda.mapper.PdaMapper;
|
import com.ruoyi.pda.mapper.PdaMapper;
|
||||||
@@ -79,6 +82,15 @@ class PdaServiceImplTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private TaskNoService taskNoService;
|
private TaskNoService taskNoService;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdCommitRecordMapper pdCommitRecordMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdDifferenceRecordMapper pdDifferenceRecordMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private PdStockpdDetailMapper pdStockpdDetailMapper;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private PdaServiceImpl service;
|
private PdaServiceImpl service;
|
||||||
|
|
||||||
@@ -407,6 +419,106 @@ class PdaServiceImplTest {
|
|||||||
verify(mydoJobService).completeJob("CK002", "2");
|
verify(mydoJobService).completeJob("CK002", "2");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void confirmInventoryRecordsDifferenceCompletesOutboundAndCreatesReturnInboundWithOriginalQuantity() {
|
||||||
|
HashMap<String, Object> inventoryDetail = new HashMap<>();
|
||||||
|
inventoryDetail.put("jobId", "PC001");
|
||||||
|
inventoryDetail.put("taskNo", "40001");
|
||||||
|
inventoryDetail.put("trayCode", "A001");
|
||||||
|
inventoryDetail.put("warehouseId", "WH01");
|
||||||
|
inventoryDetail.put("warehouseName", "一号仓");
|
||||||
|
inventoryDetail.put("quantity", "5");
|
||||||
|
inventoryDetail.put("executionPhase", "5");
|
||||||
|
when(pdaMapper.selectInventoryDetail(any(HashMap.class))).thenReturn(inventoryDetail);
|
||||||
|
|
||||||
|
HashMap<String, Object> material = new HashMap<>();
|
||||||
|
material.put("jobDetailId", "PC001-1");
|
||||||
|
material.put("stockId", "KC001");
|
||||||
|
material.put("stockDetailId", "SD001");
|
||||||
|
material.put("stockpdDetailId", "PDD001-1");
|
||||||
|
material.put("materialCode", "MAT001");
|
||||||
|
material.put("materialName", "物料1");
|
||||||
|
material.put("lotNo", "LOT1");
|
||||||
|
material.put("stockQuantity", "5");
|
||||||
|
material.put("quantity", "5");
|
||||||
|
when(pdaMapper.selectInventoryTrayMaterials(any(HashMap.class))).thenReturn(List.of(material));
|
||||||
|
when(pdaMapper.selectInventoryInboundJobByOutboundJobId("PC001")).thenReturn(null);
|
||||||
|
|
||||||
|
MydoJob outboundJob = new MydoJob();
|
||||||
|
outboundJob.setJobId("PC001");
|
||||||
|
outboundJob.setTaskNo("40001");
|
||||||
|
outboundJob.setInOrOut(30L);
|
||||||
|
outboundJob.setTrayCode("A001");
|
||||||
|
outboundJob.setWarehouseId("WH01");
|
||||||
|
outboundJob.setWarehouseName("一号仓");
|
||||||
|
outboundJob.setExitId("OUT01");
|
||||||
|
when(mydoJobService.selectMydoJobByJobId("PC001")).thenReturn(outboundJob);
|
||||||
|
when(mydoJobService.completeJob("PC001", "2")).thenReturn(AjaxResult.success());
|
||||||
|
|
||||||
|
BasStationPoint exitPoint = new BasStationPoint();
|
||||||
|
exitPoint.setPointId("OUT01");
|
||||||
|
exitPoint.setRoadwayId("R02");
|
||||||
|
when(basStationPointService.selectBasStationPointByPointId("OUT01")).thenReturn(exitPoint);
|
||||||
|
when(jobIdService.getId("PR")).thenReturn("PR001");
|
||||||
|
when(taskNoService.getTaskNo("2")).thenReturn("30001");
|
||||||
|
when(mydoJobService.insertMydoJob(any(MydoJob.class))).thenReturn(1);
|
||||||
|
when(mydoJobDetailService.insertMydoJobDetail(any(MydoJobDetail.class))).thenReturn(1);
|
||||||
|
when(mydoJobService.updateMydoJob(any(MydoJob.class))).thenReturn(1);
|
||||||
|
when(pdCommitRecordMapper.insertPdCommitRecord(any())).thenReturn(1);
|
||||||
|
when(pdDifferenceRecordMapper.insertPdDifferenceRecord(any())).thenReturn(1);
|
||||||
|
when(pdStockpdDetailMapper.updatePdStockpdDetail(any())).thenReturn(1);
|
||||||
|
when(wcsClient.sendPutawayTask(any(MydoJob.class))).thenReturn(ApiResponse.ok("OK"));
|
||||||
|
|
||||||
|
HashMap<String, Object> requestMaterial = new HashMap<>();
|
||||||
|
requestMaterial.put("jobDetailId", "PC001-1");
|
||||||
|
requestMaterial.put("stockDetailId", "SD001");
|
||||||
|
requestMaterial.put("stockpdDetailId", "PDD001-1");
|
||||||
|
requestMaterial.put("quantity", "4");
|
||||||
|
HashMap<String, Object> data = new HashMap<>();
|
||||||
|
data.put("taskNo", "40001");
|
||||||
|
data.put("barcode", "A001");
|
||||||
|
data.put("materials", List.of(requestMaterial));
|
||||||
|
|
||||||
|
service.confirmInventory(data);
|
||||||
|
|
||||||
|
verify(mydoJobService).completeJob("PC001", "2");
|
||||||
|
|
||||||
|
ArgumentCaptor<com.ruoyi.pd.commit.domain.PdCommitRecord> commitCaptor =
|
||||||
|
ArgumentCaptor.forClass(com.ruoyi.pd.commit.domain.PdCommitRecord.class);
|
||||||
|
verify(pdCommitRecordMapper).insertPdCommitRecord(commitCaptor.capture());
|
||||||
|
assertThat(commitCaptor.getValue().getStockpdDetailId()).isEqualTo("PDD001-1");
|
||||||
|
assertThat(commitCaptor.getValue().getOldQuantity()).isEqualTo(5L);
|
||||||
|
assertThat(commitCaptor.getValue().getPdQuantity()).isEqualTo(4L);
|
||||||
|
|
||||||
|
ArgumentCaptor<com.ruoyi.pd.diff.domain.PdDifferenceRecord> diffCaptor =
|
||||||
|
ArgumentCaptor.forClass(com.ruoyi.pd.diff.domain.PdDifferenceRecord.class);
|
||||||
|
verify(pdDifferenceRecordMapper).insertPdDifferenceRecord(diffCaptor.capture());
|
||||||
|
assertThat(diffCaptor.getValue().getStockpdDetailId()).isEqualTo("PDD001-1");
|
||||||
|
assertThat(diffCaptor.getValue().getStatus()).isEqualTo("0");
|
||||||
|
assertThat(diffCaptor.getValue().getRecordType()).isEqualTo("2");
|
||||||
|
assertThat(diffCaptor.getValue().getOldQuantity()).isEqualTo(5L);
|
||||||
|
assertThat(diffCaptor.getValue().getPdQuantity()).isEqualTo(4L);
|
||||||
|
|
||||||
|
ArgumentCaptor<MydoJob> jobCaptor = ArgumentCaptor.forClass(MydoJob.class);
|
||||||
|
verify(mydoJobService).insertMydoJob(jobCaptor.capture());
|
||||||
|
MydoJob inboundJob = jobCaptor.getValue();
|
||||||
|
assertThat(inboundJob.getJobId()).isEqualTo("PR001");
|
||||||
|
assertThat(inboundJob.getTaskNo()).isEqualTo("30001");
|
||||||
|
assertThat(inboundJob.getInOrOut()).isEqualTo(10L);
|
||||||
|
assertThat(inboundJob.getEntranceId()).isEqualTo("OUT01");
|
||||||
|
assertThat(inboundJob.getRoadwayId()).isEqualTo("R02");
|
||||||
|
verify(wcsClient).sendPutawayTask(inboundJob);
|
||||||
|
|
||||||
|
ArgumentCaptor<MydoJobDetail> inboundDetailCaptor = ArgumentCaptor.forClass(MydoJobDetail.class);
|
||||||
|
verify(mydoJobDetailService).insertMydoJobDetail(inboundDetailCaptor.capture());
|
||||||
|
MydoJobDetail inboundDetail = inboundDetailCaptor.getValue();
|
||||||
|
assertThat(inboundDetail.getJobId()).isEqualTo("PR001");
|
||||||
|
assertThat(inboundDetail.getInOrOutId()).isEqualTo("PC001");
|
||||||
|
assertThat(inboundDetail.getInOrOutDId()).isEqualTo("PDD001-1");
|
||||||
|
assertThat(inboundDetail.getStockinDetailId()).isEqualTo("SD001");
|
||||||
|
assertThat(inboundDetail.getInQuantity()).isEqualByComparingTo("5");
|
||||||
|
}
|
||||||
|
|
||||||
private void stubInboundStationAndRoadway() {
|
private void stubInboundStationAndRoadway() {
|
||||||
BasStationPoint point = new BasStationPoint();
|
BasStationPoint point = new BasStationPoint();
|
||||||
point.setPointId("IN01");
|
point.setPointId("IN01");
|
||||||
|
|||||||
@@ -377,14 +377,18 @@ export default {
|
|||||||
if (!this.detailLines.some(l => l.detailId === s.detailId)) {
|
if (!this.detailLines.some(l => l.detailId === s.detailId)) {
|
||||||
this.detailLines.push({
|
this.detailLines.push({
|
||||||
detailId: s.detailId,
|
detailId: s.detailId,
|
||||||
|
stockDetailId: s.detailId,
|
||||||
stockId: s.stockId,
|
stockId: s.stockId,
|
||||||
productId: s.productId,
|
productId: s.productId,
|
||||||
productName: s.productName,
|
productName: s.productName,
|
||||||
lotNo: s.lotNo || '',
|
lotNo: s.lotNo || '',
|
||||||
cargoSpaceId: s.cargoSpaceId || '',
|
cargoSpaceId: s.cargoSpaceId || '',
|
||||||
|
cargoSpaceName: s.cargoSpaceName || '',
|
||||||
trayCode: s.trayCode || '',
|
trayCode: s.trayCode || '',
|
||||||
|
warehouseId: s.warehouseId || this.mainForm.warehouseId,
|
||||||
|
warehouseName: s.warehouseName || this.mainForm.warehouseName,
|
||||||
stockQuantity: Number(s.availableQuantity != null ? s.availableQuantity : s.quantity) || 0,
|
stockQuantity: Number(s.availableQuantity != null ? s.availableQuantity : s.quantity) || 0,
|
||||||
pdQuantity: 1, // 盘点数量默认1
|
pdQuantity: Number(s.availableQuantity != null ? s.availableQuantity : s.quantity) || 1,
|
||||||
remark: ''
|
remark: ''
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -424,14 +428,18 @@ export default {
|
|||||||
const saveData = {
|
const saveData = {
|
||||||
...this.mainForm,
|
...this.mainForm,
|
||||||
details: this.detailLines.map(line => ({
|
details: this.detailLines.map(line => ({
|
||||||
stockId: line.stockId,
|
stockId: line.stockId,
|
||||||
productId: line.productId,
|
stockDetailId: line.stockDetailId || line.detailId,
|
||||||
productName: line.productName,
|
productId: line.productId,
|
||||||
lotNo: line.lotNo || null,
|
productName: line.productName,
|
||||||
cargoSpaceId: line.cargoSpaceId || null,
|
lotNo: line.lotNo || null,
|
||||||
trayCode: line.trayCode || null,
|
cargoSpaceId: line.cargoSpaceId || null,
|
||||||
quantity: line.pdQuantity, // 盘点数量
|
cargoSpaceName: line.cargoSpaceName || null,
|
||||||
remark: line.remark || null
|
warehouseId: line.warehouseId || this.mainForm.warehouseId,
|
||||||
|
warehouseName: line.warehouseName || this.mainForm.warehouseName,
|
||||||
|
trayCode: line.trayCode || null,
|
||||||
|
quantity: line.pdQuantity,
|
||||||
|
remark: line.remark || null
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
const res = await saveWithDetails(saveData)
|
const res = await saveWithDetails(saveData)
|
||||||
|
|||||||
80
sql/20260625_inventory_count_flow.sql
Normal file
80
sql/20260625_inventory_count_flow.sql
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
-- 盘点流程增强:盘点明细关联库存明细,支持盘点出库/PDA盘点/盘点回库/差异审核。
|
||||||
|
-- 可重复执行;请先在 FTC25009-WMS 的测试库验证后再上生产。
|
||||||
|
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail', 'stock_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail ADD stock_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail', 'stock_detail_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail ADD stock_detail_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail', 'cargo_space_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail ADD cargo_space_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail', 'cargo_space_name') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail ADD cargo_space_name nvarchar(255) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail', 'warehouse_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail ADD warehouse_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail', 'warehouse_name') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail ADD warehouse_name nvarchar(255) NULL;
|
||||||
|
|
||||||
|
IF OBJECT_ID('dbo.pd_stockpd_detail_finish', 'U') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail_finish', 'stock_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail_finish ADD stock_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail_finish', 'stock_detail_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail_finish ADD stock_detail_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail_finish', 'cargo_space_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail_finish ADD cargo_space_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail_finish', 'cargo_space_name') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail_finish ADD cargo_space_name nvarchar(255) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail_finish', 'warehouse_id') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail_finish ADD warehouse_id nvarchar(80) NULL;
|
||||||
|
IF COL_LENGTH('dbo.pd_stockpd_detail_finish', 'warehouse_name') IS NULL
|
||||||
|
ALTER TABLE dbo.pd_stockpd_detail_finish ADD warehouse_name nvarchar(255) NULL;
|
||||||
|
END;
|
||||||
|
|
||||||
|
EXEC(N'
|
||||||
|
UPDATE pdd
|
||||||
|
SET pdd.stock_id = bsd.stock_id,
|
||||||
|
pdd.stock_detail_id = bsd.detail_id,
|
||||||
|
pdd.cargo_space_id = bs.cargo_space_id,
|
||||||
|
pdd.cargo_space_name = bcs.cargo_space_name,
|
||||||
|
pdd.warehouse_id = bs.warehouse_id,
|
||||||
|
pdd.warehouse_name = ISNULL(NULLIF(bs.warehouse_name, ''''), bw.warehouse_name)
|
||||||
|
FROM dbo.pd_stockpd_detail pdd
|
||||||
|
INNER JOIN dbo.bas_stock bs ON bs.tray_code = pdd.tray_code
|
||||||
|
INNER JOIN dbo.bas_stock_detail bsd ON bsd.stock_id = bs.stock_id AND bsd.product_id = pdd.product_id
|
||||||
|
LEFT JOIN dbo.bas_cargo_space bcs ON bcs.cargo_space_id = bs.cargo_space_id
|
||||||
|
LEFT JOIN dbo.bas_warehouse bw ON bw.warehouse_id = bs.warehouse_id
|
||||||
|
WHERE (pdd.stock_detail_id IS NULL OR pdd.stock_detail_id = '''')
|
||||||
|
AND ISNULL(bsd.quantity, 0) > 0
|
||||||
|
');
|
||||||
|
|
||||||
|
IF OBJECT_ID('dbo.pd_stockpd_detail_finish', 'U') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
EXEC(N'
|
||||||
|
UPDATE pdd
|
||||||
|
SET pdd.stock_id = bsd.stock_id,
|
||||||
|
pdd.stock_detail_id = bsd.detail_id,
|
||||||
|
pdd.cargo_space_id = bs.cargo_space_id,
|
||||||
|
pdd.cargo_space_name = bcs.cargo_space_name,
|
||||||
|
pdd.warehouse_id = bs.warehouse_id,
|
||||||
|
pdd.warehouse_name = ISNULL(NULLIF(bs.warehouse_name, ''''), bw.warehouse_name)
|
||||||
|
FROM dbo.pd_stockpd_detail_finish pdd
|
||||||
|
INNER JOIN dbo.bas_stock bs ON bs.tray_code = pdd.tray_code
|
||||||
|
INNER JOIN dbo.bas_stock_detail bsd ON bsd.stock_id = bs.stock_id AND bsd.product_id = pdd.product_id
|
||||||
|
LEFT JOIN dbo.bas_cargo_space bcs ON bcs.cargo_space_id = bs.cargo_space_id
|
||||||
|
LEFT JOIN dbo.bas_warehouse bw ON bw.warehouse_id = bs.warehouse_id
|
||||||
|
WHERE (pdd.stock_detail_id IS NULL OR pdd.stock_detail_id = '''')
|
||||||
|
AND ISNULL(bsd.quantity, 0) > 0
|
||||||
|
');
|
||||||
|
END;
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_pd_stockpd_detail_stock_detail_id' AND object_id = OBJECT_ID('dbo.pd_stockpd_detail'))
|
||||||
|
EXEC(N'CREATE INDEX IX_pd_stockpd_detail_stock_detail_id ON dbo.pd_stockpd_detail(stock_detail_id)');
|
||||||
|
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_pd_stockpd_detail_stock_id' AND object_id = OBJECT_ID('dbo.pd_stockpd_detail'))
|
||||||
|
EXEC(N'CREATE INDEX IX_pd_stockpd_detail_stock_id ON dbo.pd_stockpd_detail(stock_id)');
|
||||||
|
|
||||||
|
IF OBJECT_ID('dbo.pd_stockpd_detail_finish', 'U') IS NOT NULL
|
||||||
|
BEGIN
|
||||||
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'IX_pd_stockpd_detail_finish_stock_detail_id' AND object_id = OBJECT_ID('dbo.pd_stockpd_detail_finish'))
|
||||||
|
EXEC(N'CREATE INDEX IX_pd_stockpd_detail_finish_stock_detail_id ON dbo.pd_stockpd_detail_finish(stock_detail_id)');
|
||||||
|
END;
|
||||||
Reference in New Issue
Block a user