diff --git a/src/main/java/com/xujie/sys/modules/ecss/controller/CoDelController.java b/src/main/java/com/xujie/sys/modules/ecss/controller/CoDelController.java index 3231bdd0..5131351d 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/controller/CoDelController.java +++ b/src/main/java/com/xujie/sys/modules/ecss/controller/CoDelController.java @@ -122,6 +122,23 @@ public class CoDelController { return R.ok(); } + @PostMapping("/modifyNotifyDetailByExcelTX") + public R modifyNotifyDetailByExcelTX(@RequestParam(value = "file") MultipartFile file, + @ModelAttribute EcssCoDelNotifyHeaderData data, + HttpServletRequest request){ + try { + Map> resultMap = coDelExcelTXService.modifyNotifyDetailByExcelTX(file, data, request); + List failList = resultMap.get("fail"); + if (failList != null && !failList.isEmpty()) { + return R.error(String.join("\n", failList)); + } + return R.ok("改单导入成功").put("resultMap", resultMap); + } catch (Exception e) { + log.error("TX改单导入失败", e); + return R.error(e.getMessage()); + } + } + @PostMapping("/updateEcssDelHeader") public R updateEcssDelHeader(@RequestBody EcssCoDelNotifyHeaderData data) { coDelService.updateEcssDelHeader(data); diff --git a/src/main/java/com/xujie/sys/modules/ecss/service/CoDelExcelTXService.java b/src/main/java/com/xujie/sys/modules/ecss/service/CoDelExcelTXService.java index 5f3b46e7..5aca378d 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/service/CoDelExcelTXService.java +++ b/src/main/java/com/xujie/sys/modules/ecss/service/CoDelExcelTXService.java @@ -16,6 +16,14 @@ public interface CoDelExcelTXService { Map> saveEcssCoDelNotifyByExcelTX(MultipartFile file, EcssCoDelNotifyHeaderData data, String deletedInvoices, HttpServletRequest request) throws Exception; + /** + * TX改单导入(重建通知单): + * 1. 继承原通知单客户信息和BU + * 2. 删除原通知单及其相关装箱/报关/UPC数据 + * 3. 按TX导入逻辑重新生成新的发货通知单 + */ + Map> modifyNotifyDetailByExcelTX(MultipartFile file, EcssCoDelNotifyHeaderData data, HttpServletRequest request) throws Exception; + void downloadDeclarationElements(HttpServletResponse response, EcssDeclarationHeaderData data); void downloadDeclaration(HttpServletResponse response, EcssDeclarationHeaderData data); diff --git a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java index 4ccb69cb..ffd65444 100644 --- a/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java +++ b/src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelTXServiceImpl.java @@ -271,6 +271,161 @@ public class CoDelExcelTXServiceImpl implements CoDelExcelTXService { return result; } + @Override + public Map> modifyNotifyDetailByExcelTX(MultipartFile file, EcssCoDelNotifyHeaderData data, HttpServletRequest request) throws Exception { + List successList = new ArrayList<>(); + List failList = new ArrayList<>(); + TransactionTemplate sheetTxTemplate = new TransactionTemplate(transactionManager); + sheetTxTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + try (Workbook workbook = WorkbookFactory.create(file.getInputStream())) { + for (int i = 0; i < workbook.getNumberOfSheets(); i++) { + Sheet sheet = workbook.getSheetAt(i); + if (sheet.getPhysicalNumberOfRows() < 2) { + continue; + } + String cmcInvoice = getInvoiceFromSheet(sheet); + try { + sheetTxTemplate.executeWithoutResult(status -> { + try { + rebuildNotifyBySheet(sheet, data, request); + } catch (Exception e) { + status.setRollbackOnly(); + throw new RuntimeException(e); + } + }); + if (StringUtils.isNotBlank(cmcInvoice)) { + successList.add(cmcInvoice); + } + } catch (Exception e) { + Throwable cause = e; + while (cause.getCause() != null) { + cause = cause.getCause(); + } + String errMsg = cause.getMessage() != null ? cause.getMessage() : e.getMessage(); + failList.add("Sheet [" + sheet.getSheetName() + "] 错误:" + errMsg); + log.error("TX改单导入失败并回滚: sheetName={}, cmcInvoice={}, err={}", sheet.getSheetName(), cmcInvoice, errMsg, e); + } + } + } + + Map> result = new HashMap<>(); + result.put("success", successList); + result.put("fail", failList); + return result; + } + + /** + * 单个Sheet执行“删除旧通知单关联数据 + 继承旧客户信息 + 重新建单” + */ + private void rebuildNotifyBySheet(Sheet sheet, EcssCoDelNotifyHeaderData requestData, HttpServletRequest request) throws Exception { + String sheetInvoice = getInvoiceFromSheet(sheet); + if (StringUtils.isBlank(sheetInvoice)) { + throw new RuntimeException("发票号为空,无法执行改单导入"); + } + + EcssCoDelNotifyHeaderData sourceHeader = resolveSourceNotifyForModify(sheetInvoice, requestData); + EcssCoDelNotifyHeaderData importData = buildModifyImportData(sourceHeader, requestData); + + clearNotifyRelatedData(sourceHeader); + processSheet(sheet, importData, request); + } + + /** + * 获取本次改单导入的原始通知单(用于继承客户信息和BU) + */ + private EcssCoDelNotifyHeaderData resolveSourceNotifyForModify(String sheetInvoice, EcssCoDelNotifyHeaderData requestData) { + if (requestData == null) { + throw new RuntimeException("请求参数为空,无法识别原发货通知单"); + } + + if (StringUtils.isNotBlank(requestData.getCmcInvoice()) + && !StringUtils.equals(requestData.getCmcInvoice(), sheetInvoice)) { + throw new RuntimeException("导入发票号[" + sheetInvoice + "]与当前选中发票号[" + requestData.getCmcInvoice() + "]不一致"); + } + + EcssCoDelNotifyHeaderData sourceHeader = null; + if (StringUtils.isNotBlank(requestData.getSite()) && StringUtils.isNotBlank(requestData.getDelNo())) { + sourceHeader = coDelMapper.getEcssCoDelNotifyHeader(requestData.getSite(), requestData.getDelNo()); + if (sourceHeader == null) { + throw new RuntimeException("未找到原发货通知单,site=" + requestData.getSite() + ",delNo=" + requestData.getDelNo()); + } + if (StringUtils.isNotBlank(sourceHeader.getCmcInvoice()) + && !StringUtils.equals(sourceHeader.getCmcInvoice(), sheetInvoice)) { + throw new RuntimeException("导入发票号[" + sheetInvoice + "]与原发货通知单发票号[" + sourceHeader.getCmcInvoice() + "]不一致"); + } + return sourceHeader; + } + + List headers = coDelMapper.checkIfHasHeader(sheetInvoice); + if (headers == null || headers.isEmpty()) { + throw new RuntimeException("未找到原发货通知单,发票号:" + sheetInvoice); + } + sourceHeader = headers.getFirst(); + if (StringUtils.isBlank(sourceHeader.getSite()) || StringUtils.isBlank(sourceHeader.getDelNo())) { + throw new RuntimeException("原发货通知单关键字段缺失,无法执行改单导入"); + } + return sourceHeader; + } + + /** + * 复制旧通知单客户内容和BU,用于新建通知单 + */ + private EcssCoDelNotifyHeaderData buildModifyImportData(EcssCoDelNotifyHeaderData sourceHeader, EcssCoDelNotifyHeaderData requestData) { + EcssCoDelNotifyHeaderData importData = new EcssCoDelNotifyHeaderData(); + importData.setSite(sourceHeader.getSite()); + importData.setBuNo(sourceHeader.getBuNo()); + importData.setCustomerName(sourceHeader.getCustomerName()); + importData.setLocalShipAddress(sourceHeader.getLocalShipAddress()); + importData.setOverseasShipper(sourceHeader.getOverseasShipper()); + importData.setOverseasAddress(sourceHeader.getOverseasAddress()); + importData.setCnative(sourceHeader.getCnative()); + importData.setSalesArea(sourceHeader.getSalesArea()); + importData.setTemplateNo(sourceHeader.getTemplateNo()); + + String username = requestData == null ? null : requestData.getUsername(); + if (StringUtils.isBlank(username)) { + SysUserEntity currentUser = (SysUserEntity) SecurityUtils.getSubject().getPrincipal(); + if (currentUser != null) { + username = currentUser.getUsername(); + } + } + importData.setUsername(username); + return importData; + } + + /** + * 删除旧通知单关联数据:报关单、装箱、UPC、发货通知单头明细 + */ + private void clearNotifyRelatedData(EcssCoDelNotifyHeaderData sourceHeader) { + log.info("开始清理旧通知单关联数据: site={}, buNo={}, delNo={}, cmcInvoice={}", + sourceHeader.getSite(), sourceHeader.getBuNo(), sourceHeader.getDelNo(), sourceHeader.getCmcInvoice()); + + EcssCoDelPalletHeaderData palletData = new EcssCoDelPalletHeaderData(); + palletData.setSite(sourceHeader.getSite()); + palletData.setBuNo(sourceHeader.getBuNo()); + palletData.setDelNo(sourceHeader.getDelNo()); + coDelMapper.deleteBoxList(palletData); + coDelMapper.deletePalletDetail(sourceHeader.getSite(), sourceHeader.getBuNo(), sourceHeader.getDelNo(), null, null); + coDelMapper.deletePalletHeader(palletData); + + if (StringUtils.isNotBlank(sourceHeader.getCmcInvoice())) { + coDelMapper.deleteUpcImportByCmcInvoice(sourceHeader.getSite(), sourceHeader.getCmcInvoice()); + } + + EcssDeclarationHeaderData declarationQuery = new EcssDeclarationHeaderData(); + declarationQuery.setSite(sourceHeader.getSite()); + declarationQuery.setDelNo(sourceHeader.getDelNo()); + EcssDeclarationHeaderData declaration = coDelMapper.getDeclarationHeaderByDelNo(declarationQuery); + if (declaration != null && StringUtils.isNotBlank(declaration.getDeclarationNo())) { + coDelMapper.deleteDeclarationHeader(declaration); + coDelMapper.deleteDeclarationDetail(declaration); + } + + coDelMapper.deleteAllEcssDelDetail(sourceHeader); + coDelMapper.deleteEcssDelHeader(sourceHeader); + } + private String getInvoiceFromSheet(Sheet sheet) { Row headerRow = sheet.getRow(0); if (headerRow == null) return null;