diff --git a/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchasePlanController.java b/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchasePlanController.java index ef3437367..5d5d80000 100644 --- a/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchasePlanController.java +++ b/klp-erp/src/main/java/com/klp/erp/controller/ErpPurchasePlanController.java @@ -142,6 +142,13 @@ public class ErpPurchasePlanController extends BaseController { return R.ok(iErpPurchasePlanService.queryDeliveryList(planId)); } + /** 刷新到货:拿已上传卷号去 WMS 钢卷表实时复核,签收入库的自动翻为已到货(无需重传) */ + @PutMapping("/{planId}/refreshArrival") + public R refreshArrival(@PathVariable Long planId) { + iErpPurchasePlanService.refreshProgress(planId); + return R.ok(); + } + /** 某计划的到货上传批次(每次上传一条,可回看) */ @GetMapping("/{planId}/deliveryBatches") public R> deliveryBatches(@PathVariable Long planId) { diff --git a/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchasePlanServiceImpl.java b/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchasePlanServiceImpl.java index 4e094e501..6e9417dca 100644 --- a/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchasePlanServiceImpl.java +++ b/klp-erp/src/main/java/com/klp/erp/service/impl/ErpPurchasePlanServiceImpl.java @@ -46,6 +46,7 @@ import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -340,7 +341,31 @@ public class ErpPurchasePlanServiceImpl implements IErpPurchasePlanService { if (valid.isEmpty()) { throw new ServiceException("未解析到有效到货数据,请检查文件内容或列名是否与模板一致"); } - // 2) kg→t 单位判定(文件级:单卷重量最大值超阈值视为 kg) + // 2) 牌号校验:到货表里的牌号必须都在本计划「采购要求」的牌号范围内 + List planItems = itemMapper.selectList(Wrappers.lambdaQuery(ErpPurchasePlanItem.class) + .eq(ErpPurchasePlanItem::getPlanId, planId)); + Set reqGrades = planItems.stream() + .map(it -> normCoil(it.getGrade())) + .filter(StringUtils::isNotBlank) + .collect(Collectors.toSet()); + if (!reqGrades.isEmpty()) { + Set badGrades = new LinkedHashSet<>(); + for (ErpPurchasePlanDeliveryImportVo r : valid) { + String g = normCoil(r.getGrade()); + if (StringUtils.isBlank(g)) { + badGrades.add("(空牌号)"); + } else if (!reqGrades.contains(g)) { + badGrades.add(r.getGrade().trim()); + } + } + if (!badGrades.isEmpty()) { + String allow = planItems.stream().map(ErpPurchasePlanItem::getGrade) + .filter(StringUtils::isNotBlank).map(String::trim).distinct().collect(Collectors.joining("、")); + throw new ServiceException("到货表中的牌号 [" + String.join("、", badGrades) + + "] 不在本计划采购要求的牌号范围内(仅允许:" + allow + "),请核对后重新上传"); + } + } + // 3) kg→t 单位判定(文件级:单卷重量最大值超阈值视为 kg) BigDecimal maxCoil = valid.stream() .map(ErpPurchasePlanDeliveryImportVo::getCoilWeight) .filter(w -> w != null) @@ -348,7 +373,7 @@ public class ErpPurchasePlanServiceImpl implements IErpPurchasePlanService { .orElse(BigDecimal.ZERO); boolean kgConverted = maxCoil.compareTo(KG_THRESHOLD) > 0; - // 3) 卷号去 WMS 钢卷表校验:存在且 data_type<>10 即视为已实际到货入库 + // 4) 卷号去 WMS 钢卷表校验:存在且 data_type<>10 即视为已实际到货入库 List uploadCoilNos = valid.stream() .map(ErpPurchasePlanDeliveryImportVo::getCoilNo) .filter(StringUtils::isNotBlank) @@ -358,13 +383,13 @@ public class ErpPurchasePlanServiceImpl implements IErpPurchasePlanService { : baseMapper.selectExistingSupplierCoilNos(uploadCoilNos).stream() .map(this::normCoil).collect(Collectors.toSet()); - // 4) 先建批次(每次上传存档,可随时回看) + // 5) 先建批次(每次上传存档,可随时回看) ErpPurchasePlanDeliveryBatch batch = new ErpPurchasePlanDeliveryBatch(); batch.setPlanId(planId); batch.setFileName(StringUtils.isNotBlank(fileName) ? fileName : "到货表"); deliveryBatchMapper.insert(batch); - // 5) 合并单元格向下填充 + 单位换算 + 落库 + WMS到货标记 + // 6) 合并单元格向下填充 + 单位换算 + 落库 + WMS到货标记 String lastTruckNo = null; BigDecimal lastTruckWeight = null; Integer lastPieceCount = null; @@ -401,10 +426,10 @@ public class ErpPurchasePlanServiceImpl implements IErpPurchasePlanService { matched++; } } - // 6) 汇总刷新进度 + // 7) 汇总刷新进度 refreshProgress(planId); - // 7) 回填批次统计(行数、WMS确认到货卷数、上传后进度快照) + // 8) 回填批次统计(行数、WMS确认到货卷数、上传后进度快照) ErpPurchasePlan after = baseMapper.selectById(planId); batch.setRowCount(count); batch.setMatchedCount(matched); @@ -492,13 +517,29 @@ public class ErpPurchasePlanServiceImpl implements IErpPurchasePlanService { if (plan == null) { return; } - // 到货 = 累计所有上传批次中 WMS 已确认到货(arrived=1)的卷 + // 到货 = 累计所有上传批次中 WMS 已确认到货的卷。 + // 每次刷新都拿卷号去 WMS 钢卷表实时复核:之前未到、后来签收入库的,这里会自动翻成已到货,无需重新上传。 List deliveries = deliveryMapper.selectList(Wrappers.lambdaQuery(ErpPurchasePlanDelivery.class) .eq(ErpPurchasePlanDelivery::getPlanId, planId)); + List coilNos = deliveries.stream() + .map(ErpPurchasePlanDelivery::getCoilNo) + .filter(StringUtils::isNotBlank) + .map(String::trim) + .collect(Collectors.toList()); + Set wmsArrivedSet = coilNos.isEmpty() ? new HashSet<>() + : baseMapper.selectExistingSupplierCoilNos(coilNos).stream() + .map(this::normCoil).collect(Collectors.toSet()); + int arrivedCount = 0; BigDecimal arrivedWeight = BigDecimal.ZERO; for (ErpPurchasePlanDelivery d : deliveries) { - if (d.getArrived() != null && d.getArrived() == 1) { + int nowArrived = StringUtils.isNotBlank(d.getCoilNo()) && wmsArrivedSet.contains(normCoil(d.getCoilNo())) ? 1 : 0; + // 状态有变化才回写,减少无谓更新 + if (d.getArrived() == null || d.getArrived() != nowArrived) { + d.setArrived(nowArrived); + deliveryMapper.updateById(d); + } + if (nowArrived == 1) { arrivedCount++; arrivedWeight = arrivedWeight.add(d.getCoilWeight() == null ? BigDecimal.ZERO : d.getCoilWeight()); } diff --git a/klp-ui/src/api/erp/purchasePlan.js b/klp-ui/src/api/erp/purchasePlan.js index 509656b2d..af269e062 100644 --- a/klp-ui/src/api/erp/purchasePlan.js +++ b/klp-ui/src/api/erp/purchasePlan.js @@ -124,6 +124,14 @@ export function listDeliveryPlans(query) { }) } +// 刷新到货(拿已上传卷号去 WMS 实时复核,签收的自动翻为已到货) +export function refreshArrival(planId) { + return request({ + url: `/erp/purchasePlan/${planId}/refreshArrival`, + method: 'put' + }) +} + // 某计划的到货上传批次(每次上传一条) export function listDeliveryBatches(planId) { return request({ diff --git a/klp-ui/src/views/erp/purchaseDelivery/index.vue b/klp-ui/src/views/erp/purchaseDelivery/index.vue index da60be0c3..cdc5dac57 100644 --- a/klp-ui/src/views/erp/purchaseDelivery/index.vue +++ b/klp-ui/src/views/erp/purchaseDelivery/index.vue @@ -59,16 +59,19 @@ {{ current.planNo }} {{ current.planStatus === '1' ? '已到齐' : '到货中' }} - - 上传到货表格 - +
+ 刷新到货 + + 上传到货表格 + +
@@ -169,7 +172,8 @@ import { getPurchasePlan, listDeliveryPlans, listDeliveryBatches, - listDeliveryByBatch + listDeliveryByBatch, + refreshArrival } from '@/api/erp/purchasePlan' import { getToken } from '@/utils/auth' @@ -188,6 +192,7 @@ export default { currentBatch: {}, batchRows: [], batchRowsLoading: false, + refreshing: false, upload: { headers: { Authorization: 'Bearer ' + getToken() } }, progressColor: '#5b8db8' } @@ -222,7 +227,11 @@ export default { this.current = { ...p } this.currentBatch = {} this.batchRows = [] - this.refreshDetail() + // 打开即静默复核一次 WMS 到货状态,保证看到的是最新 + const planId = p.planId + refreshArrival(planId).catch(() => {}).finally(() => { + if (this.current.planId === planId) this.refreshDetail() + }) }, refreshDetail() { const planId = this.current.planId @@ -230,6 +239,16 @@ export default { getPurchasePlan(planId).then(res => { this.current = { ...this.current, ...(res.data || {}) } }) this.loadBatches() }, + doRefreshArrival() { + if (!this.current.planId) return + this.refreshing = true + refreshArrival(this.current.planId).then(() => { + this.$modal.msgSuccess('已按钢卷表刷新到货状态') + this.refreshDetail() + if (this.currentBatch.batchId) this.viewBatch(this.currentBatch) + this.getList(true) + }).finally(() => { this.refreshing = false }) + }, loadBatches() { this.batchLoading = true listDeliveryBatches(this.current.planId).then(res => { @@ -302,6 +321,7 @@ $sub: #909399; p { font-size: 13px; } } .pd-d-head { display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid $line; } +.pd-head-act { display: flex; gap: 10px; align-items: center; ::v-deep .el-button { margin: 0; } } .pd-d-title { font-size: 15px; font-weight: 600; color: $ink; margin-right: 8px; } .pd-badge { font-size: 11px; line-height: 16px; padding: 0 6px; border-radius: 2px; border: 1px solid #dcdfe6; color: $sub; background: #fafafa;