feat: 新增退单操作接口及相关逻辑

主要修改:
1. 在LinkController中新增退单操作接口,支持用户对指定链接进行退单。
2. 在LinkStatusService中实现退单逻辑,确保用户只能退单自己的链接,并更新链接状态。
3. 在ScriptClient中新增调用退单接口的方法,处理与外部系统的交互。

技术细节:
- 通过新增的退单功能,提升了用户对链接的管理能力,确保操作的安全性和有效性。
This commit is contained in:
zyh
2025-08-27 19:07:37 +08:00
parent 1377c25847
commit 02c64b3a38
6 changed files with 543 additions and 1 deletions

View File

@@ -359,6 +359,29 @@ public class ScriptClient {
log.warn("获取设备状态失败: 设备={}, 错误={}", machineId, e.toString());
});
}
/**
* 调用退单接口
* @param machineId 真实设备编号 (如 f1, ss9)
* @return 退单操作结果
*/
public Mono<String> refundOrder(String machineId) {
String url = String.format(apiBaseUrl + "/yijianwan_netfile/saveMsg?文件名=判断退单&cc2=%s", machineId);
log.info("调用退单接口: 设备={}, url={}", machineId, url);
return webClient.get()
.uri(url)
.accept(MediaType.TEXT_PLAIN)
.retrieve()
.bodyToMono(String.class)
.timeout(Duration.ofSeconds(10))
.doOnSuccess(result -> {
log.info("退单接口调用成功: 设备={}, 结果={}", machineId, result);
})
.doOnError(e -> {
log.error("退单接口调用失败: 设备={}, 错误={}", machineId, e.toString());
});
}
}

View File

@@ -145,6 +145,93 @@ public class LinkStatusService {
.onErrorReturn(false);
}
/**
* 退单操作
* @param codeNo 链接编号
* @param agentId 代理ID确保用户只能退单自己的链接
* @return 退单结果
*/
@Transactional
public Mono<Boolean> refundOrder(String codeNo, Long agentId) {
return Mono.fromCallable(() -> doRefundOrder(codeNo, agentId))
.subscribeOn(Schedulers.boundedElastic());
}
private Boolean doRefundOrder(String codeNo, Long agentId) {
log.info("=== 开始处理退单操作 ===");
log.info("链接编号: {}, 代理ID: {}", codeNo, agentId);
try {
// 1. 查询链接任务
LinkTask linkTask = linkTaskMapper.findByCodeNo(codeNo);
if (linkTask == null) {
log.error("链接任务不存在: codeNo={}", codeNo);
throw new IllegalArgumentException("链接不存在");
}
// 2. 验证代理ID确保用户只能退单自己的链接
if (!linkTask.getAgentId().equals(agentId)) {
log.error("权限不足: 用户{}无权退单链接{}", agentId, codeNo);
throw new IllegalArgumentException("权限不足:您无权操作此链接");
}
// 3. 检查链接状态是否允许退单
String currentStatus = linkTask.getStatus();
if ("REFUNDED".equals(currentStatus)) {
log.warn("链接已经退过单: codeNo={}, status={}", codeNo, currentStatus);
throw new IllegalStateException("链接已经退过单");
}
if ("EXPIRED".equals(currentStatus)) {
log.warn("过期链接不允许退单: codeNo={}, status={}", codeNo, currentStatus);
throw new IllegalStateException("过期链接不允许退单");
}
if ("COMPLETED".equals(currentStatus)) {
log.warn("已完成链接不允许退单: codeNo={}, status={}", codeNo, currentStatus);
throw new IllegalStateException("已完成链接不允许退单");
}
// 4. 如果链接有关联的设备,调用脚本端退单接口
String machineId = linkTask.getMachineId();
if (machineId != null && !machineId.trim().isEmpty()) {
log.info("链接关联设备: {}, 调用脚本端退单接口", machineId);
try {
// 同步调用脚本端退单接口
String refundResult = scriptClient.refundOrder(machineId).block();
log.info("脚本端退单接口调用成功: 设备={}, 结果={}", machineId, refundResult);
} catch (Exception e) {
log.error("脚本端退单接口调用失败: 设备={}, 错误={}", machineId, e.getMessage());
// 即使脚本端调用失败,我们仍然继续更新数据库状态
// 这样可以确保用户能够看到退单状态,避免重复退单
}
} else {
log.info("链接未关联设备,跳过脚本端退单调用");
}
// 5. 更新链接状态为REFUNDED
linkTask.setStatus("REFUNDED");
linkTask.setRefundAt(LocalDateTime.now());
linkTask.setUpdatedAt(LocalDateTime.now());
int updateResult = linkTaskMapper.update(linkTask);
if (updateResult <= 0) {
log.error("更新链接状态失败: codeNo={}", codeNo);
throw new RuntimeException("更新链接状态失败");
}
log.info("退单操作成功: codeNo={}, 设备={}, 状态更新为REFUNDED", codeNo, machineId);
log.info("=== 退单操作完成 ===");
return true;
} catch (Exception e) {
log.error("=== 退单操作失败 ===");
log.error("codeNo={}, agentId={}, 错误详情: {}", codeNo, agentId, e.getMessage(), e);
throw e;
}
}
/**
* 删除链接(确保用户只能删除自己的链接)
*/