diff --git a/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java b/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java index 518c89b..10d834e 100644 --- a/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java +++ b/src/main/java/com/xujie/modules/inspection/service/impl/InspectionRequestServiceImpl.java @@ -287,9 +287,12 @@ public class InspectionRequestServiceImpl extends ServiceImpl i if(model.getId() != null){ // 编辑保存:更新 c_edit(修改时间)和 c_end_planner(修改人) PODetail existing = baseMapper.selectById(model.getId()); + if (existing == null) { + throw new RuntimeException("未找到订单明细,无法保存"); + } applyCrdOriOnUpdate(existing, model, poDetail); poDetail.setEdit(currentTimeStr); poDetail.setEndPlanner(currentUserName); baseMapper.updateById(poDetail); + if (StringUtils.hasText(poDetail.getStatus()) + && !poDetail.getStatus().equals(existing.getStatus())) { + // 订单管理当前为 header/detail 1:1,明细状态变化时必须同步头状态 + syncPoHeaderStatus(existing.getSite(), existing.getOrderNo(), poDetail.getStatus()); + } } else { // 新增保存:设置 create_time(创建时间) applyCrdOriOnCreate(model, poDetail); @@ -471,7 +479,6 @@ public class PODetailServiceImpl extends ServiceImpl i } validateNeedSubmitTestBeforeShip(existingDetail); updatePoDetailStatus(existingDetail, "已发货"); - syncPoHeaderStatusForShip(existingDetail); } private void validateNewProductAuditBeforeIssue(PODetail detail) { @@ -590,38 +597,43 @@ public class PODetailServiceImpl extends ServiceImpl i update.setEdit(currentTimeStr); update.setEndPlanner(currentUserName); baseMapper.updateById(update); - return; - } - - baseMapper.update(null, new LambdaUpdateWrapper() - .eq(PODetail::getOrderNo, existingDetail.getOrderNo()) - .eq(PODetail::getSite, existingDetail.getSite()) - .eq(PODetail::getItemNo, existingDetail.getItemNo()) - .set(PODetail::getStatus, newStatus) - .set(PODetail::getEdit, currentTimeStr) - .set(PODetail::getEndPlanner, currentUserName)); + } else { + baseMapper.update(null, new LambdaUpdateWrapper() + .eq(PODetail::getOrderNo, existingDetail.getOrderNo()) + .eq(PODetail::getSite, existingDetail.getSite()) + .eq(PODetail::getItemNo, existingDetail.getItemNo()) + .set(PODetail::getStatus, newStatus) + .set(PODetail::getEdit, currentTimeStr) + .set(PODetail::getEndPlanner, currentUserName)); + } + // 订单管理当前为 header/detail 1:1,统一在状态变更后同步头状态 + syncPoHeaderStatus(existingDetail.getSite(), existingDetail.getOrderNo(), newStatus); } /** - * @Description 发货动作后同步更新订单头状态 - * @Title syncPoHeaderStatusForShip - * @param detail 当前被发货的订单行(必须包含 site、orderNo) + * @Description 按订单号同步 POHeader 状态 + * @Title syncPoHeaderStatus + * @param site 站点 + * @param orderNo 订单号 + * @param status 目标状态 * @author rqrq - * @date 2026/07/23 + * @date 2026/07/31 * * 业务说明: - * 1) 用户从明细行执行 shipped 时,除了 PODetail.status 变更为「已发货」外,POHeader.status 也必须同步为「已发货」。 - * 2) 此处只处理 shipped 场景,不改变下达/关闭/打开等其他状态流转逻辑,避免引入额外业务口径变化。 + * 1) 当前订单管理按 header/detail 1:1 维护,任意明细状态变更都要同步头状态; + * 2) 统一收口到该方法,避免关闭/打开/下达/发货等动作出现状态不一致; * 3) 更新条件按 site + orderNo 精确命中,保证仅影响当前订单头记录。 */ - private void syncPoHeaderStatusForShip(PODetail detail) { - if (detail == null || !StringUtils.hasText(detail.getSite()) || !StringUtils.hasText(detail.getOrderNo())) { + private void syncPoHeaderStatus(String site, String orderNo, String status) { + if (!StringUtils.hasText(site) + || !StringUtils.hasText(orderNo) + || !StringUtils.hasText(status)) { return; } poHeaderMapper.update(null, new LambdaUpdateWrapper() - .eq(POHeader::getSite, detail.getSite()) - .eq(POHeader::getOrderNo, detail.getOrderNo()) - .set(POHeader::getStatus, "已发货")); + .eq(POHeader::getSite, site) + .eq(POHeader::getOrderNo, orderNo) + .set(POHeader::getStatus, status)); } @Override @@ -856,6 +868,7 @@ public class PODetailServiceImpl extends ServiceImpl i || model.getBuyer() != null || model.getCustomer() != null || model.getPoNo() != null + || StringUtils.hasText(model.getStatus()) || model.getDeparture() != null || model.getDestination() != null || model.getShipVia() != null @@ -876,6 +889,7 @@ public class PODetailServiceImpl extends ServiceImpl i header.setBuyer(model.getBuyer()); header.setCustomer(model.getCustomer()); header.setPoNo(model.getPoNo()); + header.setStatus(model.getStatus()); header.setDeparture(model.getDeparture()); header.setDestination(model.getDestination()); header.setShipVia(model.getShipVia()); diff --git a/src/main/java/com/xujie/modules/order/service/Impl/POHeaderServiceImpl.java b/src/main/java/com/xujie/modules/order/service/Impl/POHeaderServiceImpl.java index ab9d823..054c2ff 100644 --- a/src/main/java/com/xujie/modules/order/service/Impl/POHeaderServiceImpl.java +++ b/src/main/java/com/xujie/modules/order/service/Impl/POHeaderServiceImpl.java @@ -2,11 +2,14 @@ package com.xujie.modules.order.service.Impl; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.xujie.common.utils.PageUtils; +import com.xujie.modules.order.dao.PODetailMapper; import com.xujie.modules.order.dao.POHeaderMapper; +import com.xujie.modules.order.entity.PODetail; import com.xujie.modules.order.entity.POHeader; import com.xujie.modules.order.service.Iface.IPOHeaderService; import com.xujie.modules.srm.mapper.SrmSupplierMapper; @@ -18,6 +21,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; import java.time.LocalDate; import java.util.List; @@ -38,12 +42,29 @@ public class POHeaderServiceImpl extends ServiceImpl i @Autowired private SrmSupplierMapper srmSupplierMapper; + @Autowired + private PODetailMapper poDetailMapper; + @Override @Transactional public void saveModel(POHeader model){ if(model.getId() != null){ + POHeader existingHeader = baseMapper.selectById(model.getId()); + if (existingHeader == null) { + throw new RuntimeException("订单头不存在,无法保存"); + } baseMapper.updateById(model); + if (StringUtils.hasText(model.getStatus()) + && !model.getStatus().equals(existingHeader.getStatus()) + && StringUtils.hasText(existingHeader.getSite()) + && StringUtils.hasText(existingHeader.getOrderNo())) { + // 订单管理当前按 header/detail 1:1 维护,头状态变化必须同步到明细 + poDetailMapper.update(null, new LambdaUpdateWrapper() + .eq(PODetail::getSite, existingHeader.getSite()) + .eq(PODetail::getOrderNo, existingHeader.getOrderNo()) + .set(PODetail::getStatus, model.getStatus())); + } return; } diff --git a/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java b/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java index c8a3ae3..b43a60f 100644 --- a/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java +++ b/src/main/java/com/xujie/modules/qms/service/impl/QcServiceImpl.java @@ -3768,11 +3768,15 @@ public class QcServiceImpl implements QcService { try { Integer poItemNo = Integer.valueOf(qcData.getPoItemNo()); // 回滚明细 - inspectionRequestDetailMapper.rollbackInspectRequestDetail( + int rollbackCount = inspectionRequestDetailMapper.rollbackInspectRequestDetail( qcData.getSite(), qcData.getPoOrderNo(), poItemNo ); + if (rollbackCount == 0) { + throw new RuntimeException("回滚验货明细失败,未命中明细记录: requestNo=" + + qcData.getPoOrderNo() + ", itemNo=" + poItemNo); + } // 查询明细 List detailList = diff --git a/src/main/resources/mapper/order/POHeaderMapper.xml b/src/main/resources/mapper/order/POHeaderMapper.xml index a933de6..2ec08b4 100644 --- a/src/main/resources/mapper/order/POHeaderMapper.xml +++ b/src/main/resources/mapper/order/POHeaderMapper.xml @@ -162,6 +162,7 @@ buyer = #{buyer}, c_customer = #{customer}, po_no = #{poNo}, + status = #{status}, c_departure = #{departure}, c_destination = #{destination}, ship_via = #{shipVia},