fix(biz): 修复入库退料相关功能

This commit is contained in:
zxy 2026-06-02 10:32:08 +08:00
parent 437033b41e
commit 3525457c2e
10 changed files with 111 additions and 130 deletions

View File

@ -73,4 +73,6 @@ public class RawStorageMatSaveReqVO {
@Schema(description = "存货账单号")
private String inventBillNo;
private BigDecimal returnQty;
}

View File

@ -23,7 +23,7 @@ public class RawStoragePageReqVO extends PageParam {
private String billNo;
@Schema(description = "操作类型 1为入库2为出库", example = "1")
private Boolean operatorType;
private String operatorType;
@Schema(description = "业务类型 (10 采购入库11 盘盈入库12 其它入库 21 生产领料 22 盘亏出库 23采购退料)", example = "1")
private Integer businessType;

View File

@ -84,4 +84,8 @@ public class RawStorageMatPageReqVO extends PageParam {
private String billNo;
private String operatorType;
private String status;
}

View File

@ -36,8 +36,9 @@ public interface RawStorageMapper extends BaseMapperX<RawStorageDO> {
.orderByDesc(RawStorageDO::getId));
}
default String selectMaxPurReceiptNo() {
default String selectMaxPurReceiptNo(String operatorType) {
RawStorageDO rawStorageDO = selectOne(new LambdaQueryWrapperX<RawStorageDO>()
.eq(RawStorageDO::getOperatorType, operatorType)
.orderByDesc(RawStorageDO::getBillNo)
.last("LIMIT 1"));
return rawStorageDO != null ? rawStorageDO.getBillNo() : null;

View File

@ -26,6 +26,7 @@ public interface RawStorageMatMapper extends BaseMapperX<RawStorageMatDO> {
MPJLambdaWrapper<RawStorageMatDO> wrapper = new MPJLambdaWrapper<RawStorageMatDO>()
// 选择子表字段
.selectAll(RawStorageMatDO.class)
.selectAs(RawStorageMatDO::getOperatorQty, RawStorageMatRespVO::getSourceQty)
// 选择主表字段
.selectAs(RawStorageDO::getBillNo, RawStorageMatRespVO::getBillNo)
.selectAs(RawStorageDO::getOperatorType, RawStorageMatRespVO::getOperatorType)
@ -44,6 +45,9 @@ public interface RawStorageMatMapper extends BaseMapperX<RawStorageMatDO> {
.eq(StringUtils.isNotBlank(reqVO.getMatCode()), RawStorageMatDO::getMatCode, reqVO.getMatCode())
.eq(StringUtils.isNotBlank(reqVO.getInventBillNo()), RawStorageMatDO::getInventBillNo, reqVO.getInventBillNo())
// 查询条件 - 主表
.apply("operator_qty - return_qty > 0")
.eq(StringUtils.isNotBlank(reqVO.getStatus()), RawStorageDO::getStatus, reqVO.getStatus())
.eq(StringUtils.isNotBlank(reqVO.getOperatorType()), RawStorageDO::getOperatorType, reqVO.getOperatorType())
.like(StringUtils.isNotBlank(reqVO.getBillNo()), RawStorageDO::getBillNo, reqVO.getBillNo())
.orderByDesc(RawStorageMatDO::getId);

View File

@ -62,8 +62,7 @@ public class RawStorageServiceImpl implements RawStorageService {
public Integer createRawStorage(RawStorageSaveReqVO createReqVO) {
// 插入主表
RawStorageDO rawStorage = BeanUtils.toBean(createReqVO, RawStorageDO.class);
rawStorage.setBillNo(getBillNo());
rawStorage.setOperatorType("1");
rawStorage.setBillNo(getBillNo(createReqVO.getOperatorType()));
// 操作人
Long userId = getLoginUserId();
AdminUserDO adminUserDO = adminUserService.getUser(userId);
@ -72,16 +71,9 @@ public class RawStorageServiceImpl implements RawStorageService {
rawStorageMapper.insert(rawStorage);
// 插入子表
if (createReqVO.getItems() != null && !createReqVO.getItems().isEmpty()) {
for (RawStorageMatSaveReqVO matVO : createReqVO.getItems()) {
RawStorageMatDO mat = BeanUtils.toBean(matVO, RawStorageMatDO.class);
mat.setStockId(rawStorage.getId());
mat.setId(null);
rawStorageMatMapper.insert(mat);
}
}
saveMat(rawStorage.getId(), createReqVO);
if (createReqVO.getStatus().equals("2")) {
if ("2".equals(createReqVO.getStatus())) {
saveStorageLog(rawStorage);
}
@ -96,14 +88,25 @@ public class RawStorageServiceImpl implements RawStorageService {
for (RawStorageMatDO rawStorageMatDO : rawStorageMatDOS) {
RawStorageInventoryDO rawStorageInventoryDO = rawStorageInventoryService.selectByMatCodeAndBatchNo(rawStorageMatDO);
if (rawStorageInventoryDO != null) {
rawStorageInventoryDO.setYardQty(rawStorageInventoryDO.getYardQty().add(rawStorageMatDO.getOperatorQty()));
rawStorageInventoryDO.setUseQty(rawStorageInventoryDO.getUseQty().add(rawStorageMatDO.getOperatorQty()));
if ("1".equals(rawStorage.getOperatorType())) {
rawStorageInventoryDO.setYardQty(rawStorageInventoryDO.getYardQty().add(rawStorageMatDO.getOperatorQty()));
rawStorageInventoryDO.setUseQty(rawStorageInventoryDO.getUseQty().add(rawStorageMatDO.getOperatorQty()));
} else if ("2".equals(rawStorage.getOperatorType())) {
rawStorageInventoryDO.setYardQty(rawStorageInventoryDO.getYardQty().subtract(rawStorageMatDO.getOperatorQty()));
rawStorageInventoryDO.setUseQty(rawStorageInventoryDO.getUseQty().subtract(rawStorageMatDO.getOperatorQty()));
}
rawStorageInventoryService.updateRawStorageInventory(rawStorageInventoryDO);
} else {
rawStorageInventoryDO = getRawStorageInventoryDO(rawStorageMatDO);
}
rawStorageMatDO.setInventBillNo(rawStorageInventoryDO.getInventBillNo());
rawStorageMatMapper.updateById(rawStorageMatDO);
//更新源表
if ("2".equals(rawStorage.getOperatorType())) {
RawStorageMatDO sourceRawStorageMatDO = rawStorageMatMapper.selectById(rawStorageMatDO.getRelarionId());
sourceRawStorageMatDO.setReturnQty(sourceRawStorageMatDO.getReturnQty() != null ? sourceRawStorageMatDO.getReturnQty().add(rawStorageMatDO.getOperatorQty()) : rawStorageMatDO.getOperatorQty());
rawStorageMatMapper.updateById(sourceRawStorageMatDO);
}
saveStorageLog(rawStorage, rawStorageMatDO, dpstNo, rawStorageInventoryDO);
}
}
@ -142,7 +145,7 @@ public class RawStorageServiceImpl implements RawStorageService {
RawStorageLogDO rawStorageLogDO = new RawStorageLogDO();
// rawStorageLogDO.setStockId();
// rawStorageLogDO.setDescription();
rawStorageLogDO.setStatus("1");
rawStorageLogDO.setStatus("2");
rawStorageLogDO.setStoreHouseId(rawStorageMatDO.getStoreHouseId());
rawStorageLogDO.setStoreAreaId(rawStorageMatDO.getStoreAreaId());
rawStorageLogDO.setStoreHouseCd(rawStorageMatDO.getStoreHouseCd());
@ -156,8 +159,9 @@ public class RawStorageServiceImpl implements RawStorageService {
rawStorageLogDO.setUnit(rawStorageMatDO.getUnit());
rawStorageLogDO.setLotNo(rawStorageMatDO.getLotNo());
rawStorageLogDO.setOperatorQty(rawStorageMatDO.getOperatorQty());
rawStorageLogDO.setOperatorType("1");
rawStorageLogDO.setOperatorType(rawStorage.getOperatorType());
rawStorageLogDO.setBusinessType(rawStorage.getBusinessType());
// rawStorageLogDO.setStorageAft();
// rawStorageLogDO.setStorageBef();
// rawStorageLogDO.setStockItemId(rawStorageMatDO.getId());
@ -193,22 +197,25 @@ public class RawStorageServiceImpl implements RawStorageService {
if (updateReqVO.getItems() != null) {
// 删除旧子表数据
rawStorageMatMapper.deleteByStockId(updateReqVO.getId());
// 插入新子表数据
if (!updateReqVO.getItems().isEmpty()) {
for (RawStorageMatSaveReqVO matVO : updateReqVO.getItems()) {
RawStorageMatDO mat = BeanUtils.toBean(matVO, RawStorageMatDO.class);
mat.setStockId(updateReqVO.getId());
mat.setId(null);
rawStorageMatMapper.insert(mat);
}
}
saveMat(updateObj.getId(), updateReqVO);
}
if ("2".equals(updateReqVO.getStatus())) {
saveStorageLog(updateObj);
}
}
private void saveMat(Integer id, RawStorageSaveReqVO updateReqVO) {
// 插入新子表数据
if (!updateReqVO.getItems().isEmpty()) {
for (RawStorageMatSaveReqVO matVO : updateReqVO.getItems()) {
RawStorageMatDO mat = BeanUtils.toBean(matVO, RawStorageMatDO.class);
mat.setStockId(id);
mat.setId(null);
rawStorageMatMapper.insert(mat);
}
}
}
@Override
public void deleteRawStorage(Integer id) {
// 校验存在
@ -385,7 +392,7 @@ public class RawStorageServiceImpl implements RawStorageService {
private String saveRawStorage(PurReceiptDO purReceipt, String supplierNo) {
RawStorageSaveReqVO saveReqVO = new RawStorageSaveReqVO();
saveReqVO.setBillNo(getBillNo());
saveReqVO.setBillNo(getBillNo("1"));
saveReqVO.setOperatorType("1");
saveReqVO.setBusinessType("1");
saveReqVO.setRemark("");
@ -407,8 +414,12 @@ public class RawStorageServiceImpl implements RawStorageService {
// 生成订单号
// 生成入库单号
private String getBillNo() {
String maxPurReceiptNo = rawStorageMapper.selectMaxPurReceiptNo();
return CodeGenerateUtils.generateBillNo("RK", maxPurReceiptNo);
private String getBillNo(String operatorType) {
String prefix = "RK";
if ("2".equals(operatorType)) {
prefix = "CKD";
}
String maxPurReceiptNo = rawStorageMapper.selectMaxPurReceiptNo(operatorType);
return CodeGenerateUtils.generateBillNo(prefix, maxPurReceiptNo);
}
}

View File

@ -189,6 +189,7 @@ const queryParams = reactive({
billNo: undefined,
billDate: getCurrentSimMonthRange(),
status: undefined,
operatorType: "1",
})
const queryFormRef = ref() //
const exportLoading = ref(false) //

View File

@ -1,5 +1,5 @@
<template>
<Dialog :title="dialogTitle" v-model="dialogVisible" width="70%">
<Dialog :title="dialogTitle" v-model="dialogVisible" width="90%">
<el-form
ref="formRef"
:model="formData"
@ -17,7 +17,7 @@
<el-select
v-model="formData.businessType"
placeholder="请选择"
:disabled="formType === 'detail'"
:disabled="formType !== 'create'"
class="!w-full"
>
<el-option label="标准采购退料" value="3" />
@ -58,7 +58,7 @@
</el-select>
</el-form-item>
</el-col>
<el-col :span="16">
<el-col :span="8">
<el-form-item label="其它入库单" prop="relarionNo">
<el-input
v-model="formData.relarionNo"
@ -73,7 +73,7 @@
</el-row>
<el-row :gutter="20">
<el-col :span="24">
<el-col :span="16">
<el-form-item label="备注" prop="remark">
<el-input
v-model="formData.remark"
@ -122,13 +122,13 @@
</el-table-column>
<el-table-column label="已退料数量" min-width="100px" align="center">
<template #default="scope">
<span>{{ scope.row.returnedQty || '0' }}</span>
<span>{{ scope.row.returnQty || '0' }}</span>
</template>
</el-table-column>
<el-table-column label="*退料数量" min-width="120px" align="center" >
<template #default="scope" >
<MoneyInput
v-model="scope.row.returnQty"
v-model="scope.row.operatorQty"
:decimal-places="2"
:allow-negative="false"
:show-prefix="false"
@ -184,7 +184,6 @@
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button
v-if="formType !== 'detail'"
type="primary"
@ -201,6 +200,8 @@
>
确认
</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</Dialog>
@ -238,6 +239,7 @@ const formData = reactive({
relarionNo: undefined,
relarionId: undefined,
remark: undefined,
operatorType: "2",
})
//
@ -249,9 +251,6 @@ const formRules = reactive({
//
const detailList = ref<any[]>([])
//
const warehouseOptions = ref([])
// Ref
const storageSelectRef = ref()
@ -268,8 +267,6 @@ const open = async (type: string, id?: number) => {
dialogTitle.value = type === 'create' ? '新增' : type === 'update' ? '编辑' : '详情'
formType.value = type
resetForm()
await loadWarehouseList()
if (id) {
formLoading.value = true
@ -284,16 +281,6 @@ const open = async (type: string, id?: number) => {
}
defineExpose({ open })
/** 加载仓储列表 */
const loadWarehouseList = async () => {
try {
const data = await RawStorageApi.getWarehouseSelect()
warehouseOptions.value = data.list || []
} catch (error) {
console.error('加载仓储列表失败:', error)
}
}
/** 打开入库单选择弹窗 */
const openStorageSelect = () => {
storageSelectRef.value.open()
@ -325,13 +312,13 @@ const handleStorageConfirm = (storages: any[]) => {
spec: storage.spec,
unit: storage.unit,
lotNo: storage.lotNo,
returnQty: undefined,
sourceQty: storage.operatorQty || 0,
returnedQty: storage.returnedQty || 0,
returnQty: storage.returnQty || 0,
operatorQty: (storage.sourceQty || 0) - (storage.returnQty || 0),
sourceQty: storage.sourceQty || 0,
inDate: storage.billDate,
inventBillNo: storage.inventBillNo,
sourceId: storage.stockId,
relarionId: storage.stockId,
relarionId: storage.id,
areaOptions: [],
})
})
@ -342,45 +329,6 @@ const handleDeleteDetail = (index: number) => {
detailList.value.splice(index, 1)
}
/** 处理仓储变化,重新加载库区 */
const handleWarehouseChange = async (row: any) => {
row.storeAreaId = undefined
row.storeAreaName = undefined
row.storeAreCd = undefined
if (row.storeHouseId) {
const warehouse = warehouseOptions.value.find((w: any) => w.id === row.storeHouseId)
if (warehouse) {
row.storeHouseCd = warehouse.storeHouseCd
row.storeHouseName = warehouse.storeHouseName
}
try {
const list = await AreaApi.getStoreArea(row.storeHouseId)
row.areaOptions = (list || []).map((area: any) => ({
...area,
id: Number(area.id)
}))
} catch (error) {
console.error('加载库区列表失败:', error)
row.areaOptions = []
}
} else {
row.areaOptions = []
row.storeHouseCd = undefined
row.storeHouseName = undefined
}
}
/** 处理库区变化 */
const handleAreaChange = (row: any) => {
const area = row.areaOptions?.find((a: any) => a.id === row.storeAreaId)
if (area) {
row.storeAreCd = area.storeAreCd
row.storeAreaName = area.storeAreaName
}
}
/** 提交表单 */
const emit = defineEmits(['success', 'close'])
@ -396,46 +344,40 @@ const handleSubmit = async (action: string) => {
// 退
for (const item of detailList.value) {
if (!item.returnQty || item.returnQty <= 0) {
message.error('请完善退料数量')
// 退0
if (!item.operatorQty || item.operatorQty <= 0) {
message.error(`该物料(${item.matCode}退料数量不能为0请确认`)
return
}
// 退 + 退 <=
const totalReturn = (item.returnQty || 0) + (item.returnedQty || 0)
const totalReturn = (item.operatorQty || 0) + (item.returnQty || 0)
if (totalReturn > (item.sourceQty || 0)) {
message.error(`退料数量 + 已退料数量不能大于入库数量(${item.matName}`)
message.error(`物料(${item.matCode})退料数量>入库数量,请确认!`)
return
}
}
formLoading.value = true
try {
// status
const status = action === 'save' ? '1' : '2'
const submitData = {
...formData,
status,
items: detailList.value.map(item => ({
...item,
areaOptions: undefined //
}))
}
if (action === 'save') {
if (formType.value === 'create') {
await RawStorageApi.createRawStorage(submitData)
message.success(t('common.createSuccess'))
} else {
await RawStorageApi.updateRawStorage(submitData)
message.success(t('common.updateSuccess'))
}
if (formType.value === 'create') {
await RawStorageApi.createRawStorage(submitData)
message.success(t('common.createSuccess'))
} else {
//
if (formType.value === 'create') {
await RawStorageApi.confirmRawStorage(submitData)
message.success('确认成功')
} else {
await RawStorageApi.confirmRawStorage(submitData)
message.success('确认成功')
}
await RawStorageApi.updateRawStorage(submitData)
message.success(t('common.updateSuccess'))
}
dialogVisible.value = false
@ -458,6 +400,7 @@ const resetForm = () => {
relarionNo: undefined,
relarionId: undefined,
remark: undefined,
operatorType: "2",
})
detailList.value = []
formRef.value?.resetFields()

View File

@ -1,5 +1,5 @@
<template>
<Dialog :title="'选择入库单'" v-model="dialogVisible" width="90%">
<Dialog :title="'选择入库单'" v-model="dialogVisible" width="80%">
<el-form :model="queryParams" inline label-width="80px">
<el-form-item label="入库单号">
<el-input
@ -27,6 +27,7 @@
<div style="max-height: 500px; overflow-y: auto; margin-top: 15px;">
<el-table
ref="tableRef"
v-loading="loading"
:data="list"
:stripe="true"
@ -34,6 +35,7 @@
border
:highlight-current-row="true"
@selection-change="handleSelectionChange"
@row-click="handleRowClick"
@row-dblclick="handleRowDoubleClick"
style="width: 100%;"
>
@ -51,7 +53,7 @@
<el-table-column label="入库日期" align="center" prop="billDate" width="110px" />
<el-table-column label="物料编码" align="center" prop="matCode" />
<el-table-column label="物料名称" align="center" prop="matName" />
<el-table-column label="入库数量" align="center" prop="operatorQty" />
<el-table-column label="入库数量" align="center" prop="sourceQty" />
<el-table-column label="已退货数量" align="center" prop="returnQty" />
<el-table-column label="规格型号" align="center" prop="spec" />
<el-table-column label="批次号" align="center" prop="lotNo" />
@ -71,8 +73,8 @@
</div>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleConfirm" :disabled="selectedItems.length === 0">保存</el-button>
<el-button @click="dialogVisible = false">取消</el-button>
</template>
</Dialog>
</template>
@ -88,10 +90,13 @@ const loading = ref(false)
const list = ref([])
const total = ref(0)
const selectedItems = ref([])
const tableRef = ref() //
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
status: '2',
operatorType: '1',
billNo: undefined,
matName: undefined,
})
@ -131,6 +136,11 @@ const handleSelectionChange = (val: any[]) => {
selectedItems.value = val
}
const handleRowClick = (row: any) => {
//
tableRef.value?.toggleRowSelection(row)
}
const handleRowDoubleClick = (row: any) => {
selectedItems.value = [row]
emit('confirm', [row])

View File

@ -72,24 +72,24 @@
max-height="100%"
>
<el-table-column label="序号" align="center" type="index" width="60px"/>
<el-table-column label="单据类型" align="center" prop="businessType" >
<el-table-column label="业务类型" align="center" prop="businessType" >
<template #default="scope">
<span v-if="scope.row.businessType === '23'">标准采购退料</span>
<span v-else>-</span>
<span v-if="scope.row.businessType === '3'">标准采购退料</span>
<span v-if="scope.row.businessType === '4'">设备采购退料</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="退料单号" align="center" prop="billNo" />
<el-table-column label="供应商" align="center" prop="supplierName" />
<el-table-column label="单据状态" align="center" prop="status" >
<template #default="scope">
<span v-if="scope.row.status === '1'" class="text-blue">已创建</span>
<span v-else-if="scope.row.status === '2'" class="text-green">已提交</span>
<span v-else>-</span>
<span v-else></span>
</template>
</el-table-column>
<el-table-column label="退料日期" align="center" prop="billDate" />
<el-table-column label="退料人员" align="center" prop="operatorName" />
<el-table-column label="采购入库单号" align="center" prop="relarionNo" />
<el-table-column label="其他入库单号" align="center" prop="relarionNo" />
<el-table-column label="操作" align="center" >
<template #default="scope">
<el-button
@ -150,8 +150,8 @@
<el-table-column label="物料编码" align="center" prop="matCode" />
<el-table-column label="物料名称" align="center" prop="matName" />
<el-table-column label="规格型号" align="center" prop="spec" />
<el-table-column label="收货数量" align="center" prop="sourceQty" />
<el-table-column label="已退料数量" align="center" prop="returnedQty" />
<el-table-column label="来源数量" align="center" prop="operatorQty" />
<el-table-column label="已退料数量" align="center" prop="returnQty" />
<el-table-column label="退料数量" align="center" prop="returnQty" />
<el-table-column label="批次号" align="center" prop="lotNo" />
<el-table-column label="仓储名称" align="center" prop="storeHouseName" />
@ -170,6 +170,7 @@ import { ref, reactive, onMounted } from 'vue'
import * as RawStorageApi from '@/api/biz/rawstorage'
import ReturnStorageForm from './ReturnStorageForm.vue'
import { getUnitName } from '@/utils/dict'
import { getCurrentSimMonthRange } from '@/utils/formatTime'
defineOptions({ name: 'RawStorage' })
@ -186,8 +187,9 @@ const queryParams = reactive({
pageNo: 1,
pageSize: 10,
billNo: undefined,
billDate: [],
billDate: getCurrentSimMonthRange(),
status: undefined,
operatorType: "2",
})
const queryFormRef = ref() //
@ -198,8 +200,11 @@ const getList = async () => {
const data = await RawStorageApi.getRawStoragePage(queryParams)
list.value = data.list
total.value = data.total
//
if (list.value.length > 0) {
//
if (list.value.length === 0) {
detailList.value = []
} else {
//
handleRowClick(list.value[0])
}
} finally {