|
|
|
@ -50,6 +50,9 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl<QuoteDetailBomTre |
|
|
|
@Autowired |
|
|
|
private QuoteDetailToolMapper quoteDetailToolMapper; |
|
|
|
|
|
|
|
@Autowired |
|
|
|
private org.springframework.transaction.support.TransactionTemplate transactionTemplate; |
|
|
|
|
|
|
|
private Server server = null; |
|
|
|
|
|
|
|
/** IFS 成本查询并行线程数,限制 4 路并发,避免对 IFS 造成过大压力 */ |
|
|
|
@ -332,12 +335,14 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl<QuoteDetailBomTre |
|
|
|
// ========================================================================= |
|
|
|
|
|
|
|
@Override |
|
|
|
@Transactional |
|
|
|
public void changeQuoteDetailBomTree(QuoteDetailBomTree tree) { |
|
|
|
QuoteDetail detail = null; |
|
|
|
BomNodeData nodeData = null; |
|
|
|
Long newParentId = 0L; |
|
|
|
QuoteDetailBomTree bomTree = null; |
|
|
|
|
|
|
|
if (Objects.nonNull(tree.getId())) { |
|
|
|
QuoteDetailBomTree bomTree = getById(tree.getId()); |
|
|
|
bomTree = getById(tree.getId()); |
|
|
|
detail = quoteDetailService.getById(bomTree.getQuoteDetailId()); |
|
|
|
|
|
|
|
detail.setPartNo(tree.getPartNo()); |
|
|
|
@ -349,25 +354,9 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl<QuoteDetailBomTre |
|
|
|
|
|
|
|
// 先在事务外完成所有 IFS 调用和数据收集,避免 IFS 阻塞期间持有数据库行锁 |
|
|
|
Supplier<Server> ifsConFactory = resolveIfsConFactory(); |
|
|
|
Long newParentId = bomTree.getParentId(); |
|
|
|
newParentId = bomTree.getParentId(); |
|
|
|
Integer newLevel = Optional.ofNullable(tree.getLevel()).orElse(0); |
|
|
|
BomNodeData nodeData = collectBomData(detail, newParentId, newLevel, ifsConFactory); |
|
|
|
|
|
|
|
// 数据已就绪,开始执行 DML(事务持有锁的时间仅限于纯 DB 写入阶段) |
|
|
|
List<Long> ids = getAllChildIds(detail, bomTree.getId()); |
|
|
|
ids.add(bomTree.getId()); |
|
|
|
lambdaUpdate().in(QuoteDetailBomTree::getId, ids).remove(); |
|
|
|
quoteDetailBomService.lambdaUpdate().in(QuoteDetailBom::getTreeId, ids).remove(); |
|
|
|
quoteDetailRoutingService.lambdaUpdate().in(QuoteDetailRouting::getTreeId, ids).remove(); |
|
|
|
|
|
|
|
long bomId = 0; |
|
|
|
if (nodeData != null) { |
|
|
|
bomId = doSaveBomDataRecursive(nodeData, detail, newParentId); |
|
|
|
} |
|
|
|
quoteDetailBomService.lambdaUpdate() |
|
|
|
.set(QuoteDetailBom::getBomId, bomId) |
|
|
|
.eq(QuoteDetailBom::getBomId, bomTree.getId()) |
|
|
|
.update(); |
|
|
|
nodeData = collectBomData(detail, newParentId, newLevel, ifsConFactory); |
|
|
|
} else { |
|
|
|
detail = new QuoteDetail(); |
|
|
|
detail.setQuoteId(tree.getQuoteId()); |
|
|
|
@ -383,22 +372,53 @@ public class QuoteDetailBomTreeServiceImpl extends ServiceImpl<QuoteDetailBomTre |
|
|
|
|
|
|
|
// 先收集数据,再写入 |
|
|
|
Supplier<Server> ifsConFactory = resolveIfsConFactory(); |
|
|
|
BomNodeData nodeData = collectBomData(detail, 0L, 0, ifsConFactory); |
|
|
|
if (nodeData != null) { |
|
|
|
doSaveBomDataRecursive(nodeData, detail, 0L); |
|
|
|
} |
|
|
|
nodeData = collectBomData(detail, 0L, 0, ifsConFactory); |
|
|
|
} |
|
|
|
|
|
|
|
if (Boolean.TRUE.equals(tree.getRecalculateCost()) && detail != null) { |
|
|
|
log.info("[BOM_SWITCH] Recalculate cost is enabled, executing cost calculation for QuoteDetailId: {}", detail.getId()); |
|
|
|
try { |
|
|
|
quoteDetailService.queryQuoteDetailCost(detail); |
|
|
|
log.info("[BOM_SWITCH] Cost calculation completed successfully for QuoteDetailId: {}", detail.getId()); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("[BOM_SWITCH] Cost calculation failed for QuoteDetailId: {}, Error: {}", detail.getId(), e.getMessage(), e); |
|
|
|
throw new RuntimeException("成本计算失败: " + e.getMessage()); |
|
|
|
// 数据已就绪,开启短事务执行纯 DB 写入和成本计算 |
|
|
|
final QuoteDetail finalDetail = detail; |
|
|
|
final BomNodeData finalNodeData = nodeData; |
|
|
|
final Long finalNewParentId = newParentId; |
|
|
|
final QuoteDetailBomTree finalBomTree = bomTree; |
|
|
|
|
|
|
|
transactionTemplate.execute(status -> { |
|
|
|
// 1. 执行 BOM 结构切换的 DB 写入 |
|
|
|
if (Objects.nonNull(tree.getId())) { |
|
|
|
List<Long> ids = getAllChildIds(finalDetail, finalBomTree.getId()); |
|
|
|
ids.add(finalBomTree.getId()); |
|
|
|
lambdaUpdate().in(QuoteDetailBomTree::getId, ids).remove(); |
|
|
|
quoteDetailBomService.lambdaUpdate().in(QuoteDetailBom::getTreeId, ids).remove(); |
|
|
|
quoteDetailRoutingService.lambdaUpdate().in(QuoteDetailRouting::getTreeId, ids).remove(); |
|
|
|
|
|
|
|
long bomId = 0; |
|
|
|
if (finalNodeData != null) { |
|
|
|
bomId = doSaveBomDataRecursive(finalNodeData, finalDetail, finalNewParentId); |
|
|
|
} |
|
|
|
quoteDetailBomService.lambdaUpdate() |
|
|
|
.set(QuoteDetailBom::getBomId, bomId) |
|
|
|
.eq(QuoteDetailBom::getBomId, finalBomTree.getId()) |
|
|
|
.update(); |
|
|
|
} else { |
|
|
|
if (finalNodeData != null) { |
|
|
|
doSaveBomDataRecursive(finalNodeData, finalDetail, 0L); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 2. 重新计算成本 (如果开启) |
|
|
|
// 将其放在同一个事务中,如果计算失败,BOM 切换也会一并回滚,保证数据一致性 |
|
|
|
if (Boolean.TRUE.equals(tree.getRecalculateCost()) && finalDetail != null) { |
|
|
|
log.info("[BOM_SWITCH] Recalculate cost is enabled, executing cost calculation for QuoteDetailId: {}", finalDetail.getId()); |
|
|
|
try { |
|
|
|
quoteDetailService.queryQuoteDetailCost(finalDetail); |
|
|
|
log.info("[BOM_SWITCH] Cost calculation completed successfully for QuoteDetailId: {}", finalDetail.getId()); |
|
|
|
} catch (Exception e) { |
|
|
|
log.error("[BOM_SWITCH] Cost calculation failed for QuoteDetailId: {}, Error: {}", finalDetail.getId(), e.getMessage(), e); |
|
|
|
// 抛出 RuntimeException 以触发 transactionTemplate 回滚 |
|
|
|
throw new RuntimeException("成本计算失败: " + e.getMessage()); |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
// ========================================================================= |
|
|
|
|