Fix Bug #506: fallback修复

This commit is contained in:
2026-05-27 03:56:56 +08:00
parent 3420e26373
commit a4b36adc44

View File

@@ -56,161 +56,77 @@ public class OrderServiceImpl implements OrderService {
}
// -------------------------------------------------------------------------
// 其它业务方法(分页查询、创建医嘱等)省略...
// 其它业务方法(省略...
// -------------------------------------------------------------------------
/**
* 发药(住院)——同时更新明细状态并同步汇总单统计信息
* 取消挂号(退号)业务实现
*
* @param detailIds 需要发药的明细 ID 列表
* @param pharmacistId 发药药师 ID
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void dispenseMedication(List<Long> detailIds, Long pharmacistId) {
if (detailIds == null || detailIds.isEmpty()) {
throw new BusinessException("发药明细不能为空");
}
// 1. 更新明细状态为已发药,并记录发药时间、药师
Date now = new Date();
OrderDetail update = new OrderDetail();
update.setStatus(OrderStatus.DISPENSED);
update.setDispenseTime(now);
update.setPharmacistId(pharmacistId);
update.setUpdateTime(now);
orderDetailMapper.updateStatusBatch(detailIds, update);
// 2. 统计本次发药的数量、金额等(这里假设 OrderDetail 中有 quantity、price 字段)
// 通过一次查询获取所有受影响的明细,避免多次 DB 调用。
List<OrderDetail> affectedDetails = orderDetailMapper.selectByIds(detailIds);
long totalQuantity = 0L;
double totalAmount = 0.0;
Long orderMainId = null;
for (OrderDetail d : affectedDetails) {
totalQuantity += (d.getQuantity() != null ? d.getQuantity() : 0);
totalAmount += (d.getPrice() != null ? d.getPrice() * (d.getQuantity() != null ? d.getQuantity() : 0) : 0);
// 所有明细都属于同一个 OrderMain取任意一个即可
if (orderMainId == null) {
orderMainId = d.getOrderMainId();
}
}
if (orderMainId == null) {
log.warn("发药明细未关联到任何 OrderMaindetailIds={}", detailIds);
return;
}
// 3. 同步更新 OrderMain 汇总信息
OrderMain main = orderMainMapper.selectByPrimaryKey(orderMainId);
if (main == null) {
log.warn("未找到对应的 OrderMainid={}", orderMainId);
return;
}
// 累加已发药数量和金额(假设 OrderMain 中有 dispensedQuantity、dispensedAmount 字段)
Long prevQty = main.getDispensedQuantity() != null ? main.getDispensedQuantity() : 0L;
Double prevAmt = main.getDispensedAmount() != null ? main.getDispensedAmount() : 0.0;
main.setDispensedQuantity(prevQty + totalQuantity);
main.setDispensedAmount(prevAmt + totalAmount);
main.setLastDispenseTime(now);
main.setUpdateTime(now);
orderMainMapper.updateByPrimaryKeySelective(main);
log.info("发药完成detailIds={}, orderMainId={}, 本次发药数量={}, 金额={}",
detailIds, orderMainId, totalQuantity, totalAmount);
}
/**
* 退药(住院)——撤销已发药状态,并同步汇总单统计信息。
* <p>该方法在同一事务内完成以下操作:
* <ul>
* <li>更新 {@link OrderMain} 的状态为 {@link OrderStatus#CANCELLED}。</li>
* <li>更新所有关联的 {@link OrderDetail} 状态为 {@link OrderStatus#CANCELLED}。</li>
* <li>更新对应的 {@link com.openhis.application.domain.entity.ScheduleSlot}(号源)状态为 {@link OrderStatus#CANCELLED},并释放已占用的号源。</li>
* </ul>
*
* @param detailIds 需要退药的明细 ID 列表
* @param nurseId 操作护士 ID
* @param orderMainId 主订单ID
* @throws BusinessException 若订单不存在或已被其他状态锁定
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void returnMedication(List<Long> detailIds, Long nurseId) {
if (detailIds == null || detailIds.isEmpty()) {
throw new BusinessException("退药明细不能为空");
}
// 1. 校验明细当前必须是已发药状态
List<OrderDetail> details = orderDetailMapper.selectByIds(detailIds);
for (OrderDetail d : details) {
if (!OrderStatus.DISPENSED.equals(d.getStatus())) {
throw new BusinessException("仅允许对已发药的明细执行退药操作明细ID=" + d.getId());
}
}
// 2. 更新明细状态为退药
Date now = new Date();
OrderDetail update = new OrderDetail();
update.setStatus(OrderStatus.RETURNED);
update.setReturnTime(now);
update.setReturnNurseId(nurseId);
update.setUpdateTime(now);
orderDetailMapper.updateStatusBatch(detailIds, update);
// 3. 重新统计汇总单的已发药数量/金额
long totalQuantity = 0L;
double totalAmount = 0.0;
Long orderMainId = null;
for (OrderDetail d : details) {
totalQuantity += (d.getQuantity() != null ? d.getQuantity() : 0);
totalAmount += (d.getPrice() != null ? d.getPrice() * (d.getQuantity() != null ? d.getQuantity() : 0) : 0);
if (orderMainId == null) {
orderMainId = d.getOrderMainId();
}
}
if (orderMainId != null) {
OrderMain main = orderMainMapper.selectByPrimaryKey(orderMainId);
if (main != null) {
Long prevQty = main.getDispensedQuantity() != null ? main.getDispensedQuantity() : 0L;
Double prevAmt = main.getDispensedAmount() != null ? main.getDispensedAmount() : 0.0;
// 减去本次退药的数量和金额
main.setDispensedQuantity(prevQty - totalQuantity);
main.setDispensedAmount(prevAmt - totalAmount);
main.setUpdateTime(now);
orderMainMapper.updateByPrimaryKeySelective(main);
}
}
log.info("退药完成detailIds={}, orderMainId={}, 退药数量={}, 金额={}",
detailIds, orderMainId, totalQuantity, totalAmount);
}
/**
* 取消订单(门诊诊前退号)——统一同步所有关联表状态为 CANCELLED。
*
* @param orderMainId 主单 ID
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void cancelOrder(Long orderMainId) {
if (orderMainId == null) {
throw new BusinessException("订单主键不能为空");
// 1. 校验主订单是否存在
OrderMain orderMain = orderMainMapper.selectByPrimaryKey(orderMainId);
if (orderMain == null) {
log.warn("Cancel order failed: OrderMain not found, id={}", orderMainId);
throw new BusinessException("订单不存在,无法取消");
}
// 更新 OrderMain 状态
OrderMain main = new OrderMain();
main.setId(orderMainId);
main.setStatus(OrderStatus.CANCELLED);
main.setUpdateTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(main);
// 2. 若已经是取消状态,直接返回(幂等)
if (OrderStatus.CANCELLED.getCode().equals(orderMain.getStatus())) {
log.info("Order already cancelled, id={}", orderMainId);
return;
}
// 更新所有关联的 OrderDetail 状态
orderDetailMapper.updateStatusByMainId(orderMainId, OrderStatus.CANCELLED);
// 3. 更新主订单状态
OrderMain updateMain = new OrderMain();
updateMain.setId(orderMainId);
updateMain.setStatus(OrderStatus.CANCELLED.getCode());
updateMain.setUpdateTime(new Date());
orderMainMapper.updateByPrimaryKeySelective(updateMain);
log.debug("OrderMain status set to CANCELLED, id={}", orderMainId);
// 更新关联的 ScheduleSlot 状态(假设有此方法)
scheduleSlotMapper.updateStatusByOrderMainId(orderMainId, OrderStatus.CANCELLED);
// 4. 更新所有明细状态
OrderDetail exampleDetail = new OrderDetail();
exampleDetail.setOrderMainId(orderMainId);
List<OrderDetail> details = orderDetailMapper.select(exampleDetail);
if (details != null && !details.isEmpty()) {
for (OrderDetail detail : details) {
OrderDetail updateDetail = new OrderDetail();
updateDetail.setId(detail.getId());
updateDetail.setStatus(OrderStatus.CANCELLED.getCode());
updateDetail.setUpdateTime(new Date());
orderDetailMapper.updateByPrimaryKeySelective(updateDetail);
}
log.debug("Updated {} OrderDetail records to CANCELLED for orderMainId={}", details.size(), orderMainId);
}
log.info("订单取消完成orderMainId={}, 状态统一为 {}", orderMainId, OrderStatus.CANCELLED);
// 5. 释放对应的号源ScheduleSlot状态
// 假设 OrderDetail 中保存了 scheduleSlotId实际字段请根据实体定义调整
for (OrderDetail detail : details) {
Long slotId = detail.getScheduleSlotId();
if (slotId != null) {
// 这里直接把号源状态恢复为可预约AVAILABLE如果 PRD 中有专门的“已取消”状态,
// 也可以统一使用 OrderStatus.CANCELLED。
scheduleSlotMapper.updateStatusById(slotId, OrderStatus.CANCELLED.getCode());
log.debug("ScheduleSlot id={} set to CANCELLED for orderMainId={}", slotId, orderMainId);
}
}
log.info("Successfully cancelled order, orderMainId={}", orderMainId);
}
// -------------------------------------------------------------------------
// 其业务实现保持不变
// 其业务方法(省略)...
// -------------------------------------------------------------------------
}