From da6ce98e517fc7d72d5abf329c43d2268227dbc1 Mon Sep 17 00:00:00 2001 From: "han\\hanst" Date: Mon, 6 Oct 2025 09:58:51 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=87=E8=B4=AD=E6=8E=A5=E6=94=B6=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E5=8F=96=E6=B6=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/QualifiedStorageServiceImpl.java | 21 +- .../po/service/impl/PoServiceImpl.java | 8 +- .../impl/PurchaseManageServiceImpl.java | 161 ++++--------- .../scrap/service/impl/ScrapServiceImpl.java | 13 +- .../modules/trans/entity/TransDetailDto.java | 1 + .../mapper/procurement/PoReceiptMapper.xml | 212 +++++++++--------- 6 files changed, 179 insertions(+), 237 deletions(-) diff --git a/src/main/java/com/gaotao/modules/inspection/service/impl/QualifiedStorageServiceImpl.java b/src/main/java/com/gaotao/modules/inspection/service/impl/QualifiedStorageServiceImpl.java index d2fc9c6..b3209f5 100644 --- a/src/main/java/com/gaotao/modules/inspection/service/impl/QualifiedStorageServiceImpl.java +++ b/src/main/java/com/gaotao/modules/inspection/service/impl/QualifiedStorageServiceImpl.java @@ -1,6 +1,8 @@ package com.gaotao.modules.inspection.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.gaotao.common.exception.XJException; import com.gaotao.common.utils.IfsErrorMessageUtils; import com.gaotao.common.utils.R; @@ -353,6 +355,18 @@ public class QualifiedStorageServiceImpl implements QualifiedStorageService { String result = ifsApiIssueAndReturnService.purchaseOrderMoveToStockOneLocation(moveDto); if ("IFSUpdated".equals(result) || "\"IFSUpdated\"".equals(result)) { + // 8. IFS接口调用成功后,更新接收记录状态 + LambdaUpdateWrapper receiptDetailQueryWrapper = Wrappers.lambdaUpdate(); + receiptDetailQueryWrapper.eq(PoReceiptDetail::getSite, site) + .eq(PoReceiptDetail::getOrderNo, sourceRef1) + .eq(PoReceiptDetail::getOrderItemNo, sourceRef2) + .eq(PoReceiptDetail::getOrderReleaseNo, sourceRef3) + .eq(PoReceiptDetail::getItemNo, receiptNo); + + PoReceiptDetail poReceiptDetail = new PoReceiptDetail(); + poReceiptDetail.setStatus("RECEIVED"); // 设置为已入库 + poReceiptDetailService.update(poReceiptDetail, receiptDetailQueryWrapper); + log.info("检验合格入库成功,事务号: {}, HandlingUnit数量: {}", inboundTransNo, handlingUnits.size()); return R.ok("检验合格入库成功"); } else { @@ -360,7 +374,6 @@ public class QualifiedStorageServiceImpl implements QualifiedStorageService { String errorMessage = IfsErrorMessageUtils.extractOracleErrorMessage(result); throw new XJException("IFS移库失败: " + errorMessage); } - } catch (Exception e) { log.error("检验合格入库失败: {}", e.getMessage()); throw new RuntimeException(e.getMessage(), e); @@ -375,19 +388,19 @@ public class QualifiedStorageServiceImpl implements QualifiedStorageService { // 直接在此方法中实现库存创建逻辑,使用带行锁的库存操作,防止并发 String site = transDetail.getSite(); String locationId = transDetail.getLocationId(); - + // 根据库位获取仓库ID String warehouseId = null; Location location = locationService.getByLocationIdAndSite(site, locationId); if (location != null) { warehouseId = location.getWarehouseId(); } - + // 如果根据库位获取不到仓库,则使用transHeader中的仓库ID作为备用 if (StringUtils.isBlank(warehouseId)) { warehouseId = transHeader.getWarehouseId(); } - + String partNo = transDetail.getPartNo(); String batchNo = transDetail.getBatchNo(); String wdr = firstHu.getWdr() != null ? firstHu.getWdr() : "*"; diff --git a/src/main/java/com/gaotao/modules/po/service/impl/PoServiceImpl.java b/src/main/java/com/gaotao/modules/po/service/impl/PoServiceImpl.java index 631a1a6..404ea22 100644 --- a/src/main/java/com/gaotao/modules/po/service/impl/PoServiceImpl.java +++ b/src/main/java/com/gaotao/modules/po/service/impl/PoServiceImpl.java @@ -326,19 +326,19 @@ public class PoServiceImpl extends ServiceImpl implemen // 直接在此方法中实现库存创建逻辑,使用带行锁的库存操作,防止并发 String site = inData.getSite(); String locationId = inData.getLocationNo(); - + // 根据库位获取仓库ID String warehouseId = null; Location location = locationService.getByLocationIdAndSite(site, locationId); if (location != null) { warehouseId = location.getWarehouseId(); } - + // 如果根据库位获取不到仓库,则使用transHeader中的仓库ID作为备用 if (StringUtils.isBlank(warehouseId)) { warehouseId = transHeader.getWarehouseId(); } - + String partNo = inData.getPartNo(); String batchNo = inData.getBatchNo(); String wdr = inData.getWdr(); @@ -560,7 +560,7 @@ public class PoServiceImpl extends ServiceImpl implemen poReceiptDetail.setPartNo(inData.getPartNo()); poReceiptDetail.setPartDesc(inData.getPartDesc()); // 基本字段设置 - poReceiptDetail.setArriveQty(inData.getTransQty()); + poReceiptDetail.setArriveQty(inData.getQtyToReceive()); poReceiptDetail.setQtyInspectedNew(BigDecimal.valueOf(0.0)); poReceiptDetail.setPoumId(inData.getPurchaseUOM() != null ? inData.getPurchaseUOM() : ""); poReceiptDetail.setConvertFactor(inData.getConvertFactor() != null ? inData.getConvertFactor() : 1); diff --git a/src/main/java/com/gaotao/modules/po/service/impl/PurchaseManageServiceImpl.java b/src/main/java/com/gaotao/modules/po/service/impl/PurchaseManageServiceImpl.java index b756ef4..928fad4 100644 --- a/src/main/java/com/gaotao/modules/po/service/impl/PurchaseManageServiceImpl.java +++ b/src/main/java/com/gaotao/modules/po/service/impl/PurchaseManageServiceImpl.java @@ -7,10 +7,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.gaotao.common.exception.XJException; -import com.gaotao.common.utils.DateUtils; -import com.gaotao.common.utils.HttpUtils; -import com.gaotao.common.utils.PageUtils; -import com.gaotao.common.utils.R; +import com.gaotao.common.utils.*; import com.gaotao.modules.inspection.service.IfsInspectionHistoryService; import com.gaotao.modules.po.dao.PoReceiptDetailMapper; import com.gaotao.modules.po.dao.PoReceiptMapper; @@ -69,7 +66,7 @@ public class PurchaseManageServiceImpl implements PurchaseManageService { @Value("${custom.ifs-domainUserID}") private String domainUserID; - + @Value("${ldap-control.control-flag:false}") private Boolean ldapFlag; @@ -89,7 +86,7 @@ public class PurchaseManageServiceImpl implements PurchaseManageService { } return domainUserID; } - + @Override public PageUtils getReceiptRecordList(PoReceiptQueryDto queryDto) { IPage> page = poReceiptMapper.getReceiptRecordList( @@ -133,7 +130,7 @@ public class PurchaseManageServiceImpl implements PurchaseManageService { @Override public PageUtils getCancelableReceiptList(PoReceiptQueryDto queryDto) { // 只查询状态为已接收且未取消的记录 - queryDto.setStatus("RECEIVED"); + queryDto.setStatus("ARRIVED"); IPage> page = poReceiptMapper.getCancelableReceiptList( new Page<>(queryDto.getPage(), queryDto.getSize()), queryDto); return new PageUtils(page); @@ -148,17 +145,11 @@ public class PurchaseManageServiceImpl implements PurchaseManageService { String cancelReason = (String) params.get("cancelReason"); Double itemNo = params.get("itemNo") != null ? Double.valueOf(params.get("itemNo").toString()) : null; - // 1. 条件校验:验证库存 - R validationResult = validateInventoryForCancel(receiptNo, site, itemNo); - if ((int)validationResult.get("code") != 0) { - return validationResult; - } - // 2. 调用IFS接口同步取消操作 syncCancelToIfs(receiptNo, site, itemNo, cancelReason); // 3. 更新本地记录状态 - updateLocalRecordStatus(receiptNo, site, itemNo, "CANCELLED", cancelReason); + updateLocalRecordStatus(receiptNo, site, itemNo, "CANCEL", cancelReason); return R.ok("取消接收成功"); @@ -209,67 +200,46 @@ public class PurchaseManageServiceImpl implements PurchaseManageService { return poReceiptDetailMapper.getInspectionRecordsByReceiptNo(receiptNo, site); } - /** - * 验证库存是否可以取消 - */ - private R validateInventoryForCancel(String receiptNo, String site, Double itemNo) { - // 获取接收记录明细 - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(PoReceiptDetail::getReceiptNo, receiptNo) - .eq(PoReceiptDetail::getSite, site); - if (itemNo != null) { - wrapper.eq(PoReceiptDetail::getItemNo, itemNo); - } - List details = poReceiptDetailMapper.selectList(wrapper); - - for (PoReceiptDetail detail : details) { - // 检查库存位置、批号和数量是否满足取消条件 - LambdaQueryWrapper stockWrapper = new LambdaQueryWrapper<>(); - stockWrapper.eq(InventoryStock::getSite, site) - .eq(InventoryStock::getPartNo, detail.getPartNo()) - .eq(InventoryStock::getBatchNo, detail.getBatchNo()) - .eq(InventoryStock::getLocationId, detail.getLocationId()); - - InventoryStock stock = inventoryStockMapper.selectOne(stockWrapper); - if (stock == null) { - return R.error("物料 " + detail.getPartNo() + " 在库位 " + detail.getLocationId() + " 的库存不存在"); - } - - if (stock.getQtyOnHand().compareTo(detail.getQtyReceived()) < 0) { - return R.error("物料 " + detail.getPartNo() + " 库存数量不足,无法取消接收"); - } - } - - return R.ok(); - } /** * 同步取消操作到IFS */ private void syncCancelToIfs(String receiptNo, String site, Double itemNo, String cancelReason) { try { - Map params = Map.of( - "ifsDBName", ifsDBName, - "domainUserID", getCurrentDomainUserID(), - "ifsSiteID", site, - "receiptNo", receiptNo, - "itemNo", itemNo != null ? itemNo : 0, - "cancelReason", cancelReason - ); - - ObjectMapper objectMapper = new ObjectMapper(); - String jsonBody = objectMapper.writeValueAsString(params); - String response = HttpUtils.doPost(ifsUrl + "CancelReceipt", jsonBody, null); - - // 解析响应 - Map responseData = objectMapper.readValue(response, new TypeReference<>() {}); - Boolean success = (Boolean) responseData.get("success"); - - if (success != null && success) { - log.info("IFS同步成功"); - } else { - String errorMsg = (String) responseData.get("message"); - throw new XJException("IFS同步失败: " + errorMsg); + // 根据receiptNo、site、itemNo查询PoReceiptDetail记录,获取订单相关信息 + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(PoReceiptDetail::getReceiptNo, receiptNo) + .eq(PoReceiptDetail::getSite, site); + if (itemNo != null) { + wrapper.eq(PoReceiptDetail::getItemNo, itemNo); + } + + List details = poReceiptDetailMapper.selectList(wrapper); + if (details.isEmpty()) { + throw new XJException("未找到对应的接收记录"); + } + + // 对每个接收记录调用IFS取消方法 + for (PoReceiptDetail detail : details) { + Map params = Map.of( + "ifsDBName", ifsDBName, + "domainUserID", getCurrentDomainUserID(), + "ifsSiteID", site, + "ifsReceiptSequence", "2690471" + ); + + ObjectMapper objectMapper = new ObjectMapper(); + String jsonBody = objectMapper.writeValueAsString(params); + String ifsResponse = HttpUtils.doPost(ifsUrl + "CancelPurchaseOrderArrival", jsonBody, null); + + if ("IFSUpdated".equals(ifsResponse) || "\"IFSUpdated\"".equals(ifsResponse)) { + log.info("IFS取消接收成功,PO号: {}", detail.getOrderNo()); + } else { + log.error("IFS取消接收失败,PO号: {}, 响应: {}", detail.getOrderNo(), ifsResponse); + // 同步失败需要回滚前面所有的数据库操作 + String errorMessage = IfsErrorMessageUtils.extractOracleErrorMessage(ifsResponse); + throw new XJException(errorMessage); + } } } catch (Exception e) { @@ -295,57 +265,4 @@ public class PurchaseManageServiceImpl implements PurchaseManageService { poReceiptDetailMapper.update(detail, detailWrapper); } - /** - * 从IFS获取检验数据 - */ - private List> getIfsInspectionData(String site) { - try { - Map params = Map.of( - "ifsDBName", ifsDBName, - "domainUserID", getCurrentDomainUserID(), - "ifsSiteID", site - ); - - ObjectMapper objectMapper = new ObjectMapper(); - String jsonBody = objectMapper.writeValueAsString(params); - String response = HttpUtils.doGetWithBody(ifsUrl + "InspectionResults", jsonBody, null); - - return objectMapper.readValue(response, new TypeReference<>() {}); - - } catch (Exception e) { - log.error("获取IFS检验数据异常: {}", e.getMessage(), e); - return new ArrayList<>(); - } - } - - /** - * 更新本地检验记录 - */ - private int updateLocalInspectionRecords(List> inspectionData) { - int updatedCount = 0; - - for (Map data : inspectionData) { - String receiptNo = (String) data.get("receiptNo"); - String site = (String) data.get("site"); - Double itemNo = (Double) data.get("itemNo"); - BigDecimal qtyApproved = new BigDecimal(data.get("qtyApproved").toString()); - String inspectionRemark = (String) data.get("inspectionRemark"); - - // 更新对应的接收明细记录 - LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - wrapper.eq(PoReceiptDetail::getReceiptNo, receiptNo) - .eq(PoReceiptDetail::getSite, site) - .eq(PoReceiptDetail::getItemNo, itemNo); - - PoReceiptDetail detail = new PoReceiptDetail(); - detail.setQtyApproved(qtyApproved); - detail.setRemark2(inspectionRemark); - detail.setInspectionTime(new Date()); - - int updated = poReceiptDetailMapper.update(detail, wrapper); - updatedCount += updated; - } - - return updatedCount; - } } diff --git a/src/main/java/com/gaotao/modules/scrap/service/impl/ScrapServiceImpl.java b/src/main/java/com/gaotao/modules/scrap/service/impl/ScrapServiceImpl.java index c262d50..eb028f9 100644 --- a/src/main/java/com/gaotao/modules/scrap/service/impl/ScrapServiceImpl.java +++ b/src/main/java/com/gaotao/modules/scrap/service/impl/ScrapServiceImpl.java @@ -20,6 +20,8 @@ import com.gaotao.modules.sys.controller.AbstractController; import com.gaotao.modules.handlingunit.entity.HandlingUnit; import com.gaotao.modules.handlingunit.service.HandlingUnitService; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.gaotao.modules.warehouse.entity.InventoryStock; import com.gaotao.modules.warehouse.service.InventoryStockService; import org.apache.shiro.SecurityUtils; @@ -231,7 +233,16 @@ public class ScrapServiceImpl extends AbstractController implements ScrapService stock.setOutQty((stock.getOutQty() != null ? stock.getOutQty() : BigDecimal.ZERO).add(label.getQuantity())); stock.setLatestOutDate(new Date()); - inventoryStockService.updateById(stock); + // 使用复合主键条件更新库存记录 + LambdaUpdateWrapper updateWrapper = Wrappers.lambdaUpdate(); + updateWrapper.eq(InventoryStock::getSite, site) + .eq(InventoryStock::getWarehouseId, label.getWarehouseId()) + .eq(InventoryStock::getPartNo, label.getPartNo()) + .eq(InventoryStock::getBatchNo, label.getBatchNo()) + .eq(InventoryStock::getLocationId, label.getLocationId()) + .eq(InventoryStock::getWdr, handlingUnit.getWdr() != null ? handlingUnit.getWdr() : "*"); + + inventoryStockService.update(stock, updateWrapper); log.info("库存更新成功 - 物料: {}, 批次: {}, 库位: {}, WDR: {}, 原库存: {}, 报废数量: {}, 新库存: {}", label.getPartNo(), label.getBatchNo(), label.getLocationId(), handlingUnit.getWdr() != null ? handlingUnit.getWdr() : "", currentQty, label.getQuantity(), newQty); diff --git a/src/main/java/com/gaotao/modules/trans/entity/TransDetailDto.java b/src/main/java/com/gaotao/modules/trans/entity/TransDetailDto.java index c162e96..857081f 100644 --- a/src/main/java/com/gaotao/modules/trans/entity/TransDetailDto.java +++ b/src/main/java/com/gaotao/modules/trans/entity/TransDetailDto.java @@ -28,6 +28,7 @@ public class TransDetailDto extends TransDetail{ private String inventoryPartDB; // 库存物料DB private String partDesc; // 物料描述 private String wdr; // WDR + private BigDecimal qtyToReceive; // 待接收数量 private String samplePercent; // 抽样百分比 private String sampleQty; // 抽样数量 diff --git a/src/main/resources/mapper/procurement/PoReceiptMapper.xml b/src/main/resources/mapper/procurement/PoReceiptMapper.xml index 9e986ce..ada2cf3 100644 --- a/src/main/resources/mapper/procurement/PoReceiptMapper.xml +++ b/src/main/resources/mapper/procurement/PoReceiptMapper.xml @@ -5,62 +5,62 @@ - SELECT + SELECT prd.site, - prd.receipt_no, - prd.item_no, - prd.part_no, - prd.arrive_qty, - prd.qty_inspected_new, - prd.poum_id, - prd.convert_factor, + prd.receipt_no AS receiptNo, + prd.item_no AS itemNo, + prd.part_no AS partNo, + prd.arrive_qty AS arriveQty, + prd.qty_inspected_new AS qtyInspectedNew, + prd.poum_id AS poumId, + prd.convert_factor AS convertFactor, prd.status, - prd.need_inspect_flag, - prd.inspect_code, - prd.qty_sample, - prd.percent_sample, - prd.qty_to_inspect, - prd.qty_inspected, - prd.qty_approved, - prd.qty_returned, - prd.qty_replace, - prd.qty_scrapt, - prd.qty_to_received, - prd.qty_received, - prd.invoice_qty, - prd.invoice_price, - prd.invoice_no, - prd.location_id, - prd.order_no, - prd.order_item_no, - prd.cance_iremark, - prd.batch_no, - prd.manu_facture_date, - prd.expired_date, - prd.sample_inspection_method_id, - prd.sample_inspection_level_no, + prd.need_inspect_flag AS needInspectFlag, + prd.inspect_code AS inspectCode, + prd.qty_sample AS qtySample, + prd.percent_sample AS percentSample, + prd.qty_to_inspect AS qtyToInspect, + prd.qty_inspected AS qtyInspected, + prd.qty_approved AS qtyApproved, + prd.qty_returned AS qtyReturned, + prd.qty_replace AS qtyReplace, + prd.qty_scrapt AS qtyScrapt, + prd.qty_to_received AS qtyToReceived, + prd.qty_received AS qtyReceived, + prd.invoice_qty AS invoiceQty, + prd.invoice_price AS invoicePrice, + prd.invoice_no AS invoiceNo, + prd.location_id AS locationId, + prd.order_no AS orderNo, + prd.order_item_no AS orderItemNo, + prd.cance_iremark AS canceIremark, + prd.batch_no AS batchNo, + prd.manu_facture_date AS manuFactureDate, + prd.expired_date AS expiredDate, + prd.sample_inspection_method_id AS sampleInspectionMethodId, + prd.sample_inspection_level_no AS sampleInspectionLevelNo, prd.remark, - prd.to_inv_nofity_qty, - prd.inv_notify_qty, - prd.inspect_type_db, - prd.inspect_type, - prd.need_receive_flag, - prd.to_invoice_qty, - prd.qty_rbjs, + prd.to_inv_nofity_qty AS toInvNofityQty, + prd.inv_notify_qty AS invNotifyQty, + prd.inspect_type_db AS inspectTypeDb, + prd.inspect_type AS inspectType, + prd.need_receive_flag AS needReceiveFlag, + prd.to_invoice_qty AS toInvoiceQty, + prd.qty_rbjs AS qtyRbjs, prd.orderfef1, prd.orderfef2, - prd.orderfef_type, - prd.price_no_tax, + prd.orderfef_type AS orderfefType, + prd.price_no_tax AS priceNoTax, prd.status2, - prd.check_by, + prd.check_by AS checkBy, prd.remark2, prd.inspector, - prd.inspection_time, - pr.receive_date, - pr.supplier_id, + prd.inspection_time AS inspectionTime, + pr.receive_date AS receiveDate, + pr.supplier_id AS supplierId, pr.receiver, - pr.delivery_note_no, - pr.warehouse_id + pr.delivery_note_no AS deliveryNoteNo, + pr.warehouse_id AS warehouseId FROM po_receipt_detail prd INNER JOIN po_receipt pr ON prd.receipt_no = pr.receipt_no AND prd.site = pr.site - AND prd.status = 'RECEIVED' + AND prd.status = 'ARRIVED' AND prd.qty_received > 0 AND prd.site = #{params.site} @@ -185,21 +185,21 @@