|
@@ -1,6 +1,7 @@
|
|
|
package com.payment.platform.module.payment.facetoface.service;
|
|
package com.payment.platform.module.payment.facetoface.service;
|
|
|
|
|
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
|
|
|
+import cn.hutool.core.bean.copier.CopyOptions;
|
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
import com.alipay.api.AlipayApiException;
|
|
import com.alipay.api.AlipayApiException;
|
|
|
import com.alipay.api.domain.*;
|
|
import com.alipay.api.domain.*;
|
|
@@ -10,6 +11,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
import com.payment.platform.common.exception.BusinessException;
|
|
import com.payment.platform.common.exception.BusinessException;
|
|
|
import com.payment.platform.common.response.PageResult;
|
|
import com.payment.platform.common.response.PageResult;
|
|
|
|
|
+import com.payment.platform.common.utils.RedisLockUtil;
|
|
|
import com.payment.platform.core.alipay.AlipayClientFactory;
|
|
import com.payment.platform.core.alipay.AlipayClientFactory;
|
|
|
import com.payment.platform.module.payment.facetoface.dto.*;
|
|
import com.payment.platform.module.payment.facetoface.dto.*;
|
|
|
import com.payment.platform.module.payment.facetoface.entity.FacetofaceOrderEntity;
|
|
import com.payment.platform.module.payment.facetoface.entity.FacetofaceOrderEntity;
|
|
@@ -35,6 +37,10 @@ public class FacetofaceService {
|
|
|
|
|
|
|
|
private final FacetofaceOrderMapper mapper;
|
|
private final FacetofaceOrderMapper mapper;
|
|
|
private final AlipayClientFactory alipayClientFactory;
|
|
private final AlipayClientFactory alipayClientFactory;
|
|
|
|
|
+ private final RedisLockUtil redisLockUtil;
|
|
|
|
|
+
|
|
|
|
|
+ /** 最大轮询次数 — 超过此值未到达终态则自动关闭 */
|
|
|
|
|
+ private static final int MAX_QUERY_COUNT = 50;
|
|
|
|
|
|
|
|
// ==================== 查询 ====================
|
|
// ==================== 查询 ====================
|
|
|
|
|
|
|
@@ -83,133 +89,143 @@ public class FacetofaceService {
|
|
|
*/
|
|
*/
|
|
|
@Transactional
|
|
@Transactional
|
|
|
public F2fOrderVO apply(F2fOrderCreateDTO dto) {
|
|
public F2fOrderVO apply(F2fOrderCreateDTO dto) {
|
|
|
- // 检查同一企业是否有进行中的申请
|
|
|
|
|
- FacetofaceOrderEntity active = mapper.selectOne(
|
|
|
|
|
- new LambdaQueryWrapper<FacetofaceOrderEntity>()
|
|
|
|
|
- .eq(FacetofaceOrderEntity::getEnterpriseId, dto.getEnterpriseId())
|
|
|
|
|
- .ne(FacetofaceOrderEntity::getOrderStatus, FacetofaceOrderStatus.CLOSED.getValue())
|
|
|
|
|
- .orderByDesc(FacetofaceOrderEntity::getId)
|
|
|
|
|
- .last("LIMIT 1"));
|
|
|
|
|
- if (active != null) {
|
|
|
|
|
- throw new BusinessException(400, "该企业已有进行中的当面付申请");
|
|
|
|
|
|
|
+ String lockKey = "f2f:apply:" + dto.getEnterpriseId();
|
|
|
|
|
+ String lockValue = redisLockUtil.lock(lockKey, 30);
|
|
|
|
|
+ if (lockValue == null) {
|
|
|
|
|
+ throw new BusinessException(400, "该企业正在处理中,请稍后再试");
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // 查询同一企业是否有历史 CLOSED 申请单(用于复用更新而非插新行)
|
|
|
|
|
- FacetofaceOrderEntity closedOrder = mapper.selectOne(
|
|
|
|
|
- new LambdaQueryWrapper<FacetofaceOrderEntity>()
|
|
|
|
|
- .eq(FacetofaceOrderEntity::getEnterpriseId, dto.getEnterpriseId())
|
|
|
|
|
- .eq(FacetofaceOrderEntity::getOrderStatus, FacetofaceOrderStatus.CLOSED.getValue())
|
|
|
|
|
- .orderByDesc(FacetofaceOrderEntity::getId)
|
|
|
|
|
- .last("LIMIT 1"));
|
|
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
- // Step 1: 创建应用事务
|
|
|
|
|
- AlipayOpenAgentCreateModel createModel = new AlipayOpenAgentCreateModel();
|
|
|
|
|
- createModel.setAccount(dto.getAccount());
|
|
|
|
|
- ContactModel contactInfo = new ContactModel();
|
|
|
|
|
- contactInfo.setContactName(dto.getContactName());
|
|
|
|
|
- contactInfo.setContactMobile(dto.getContactMobile());
|
|
|
|
|
- if (StrUtil.isNotBlank(dto.getContactEmail())) {
|
|
|
|
|
- contactInfo.setContactEmail(dto.getContactEmail());
|
|
|
|
|
- }
|
|
|
|
|
- createModel.setContactInfo(contactInfo);
|
|
|
|
|
- if (StrUtil.isNotBlank(dto.getOrderTicket())) {
|
|
|
|
|
- createModel.setOrderTicket(dto.getOrderTicket());
|
|
|
|
|
|
|
+ // 检查同一企业是否有进行中的申请
|
|
|
|
|
+ FacetofaceOrderEntity active = mapper.selectOne(
|
|
|
|
|
+ new LambdaQueryWrapper<FacetofaceOrderEntity>()
|
|
|
|
|
+ .eq(FacetofaceOrderEntity::getEnterpriseId, dto.getEnterpriseId())
|
|
|
|
|
+ .ne(FacetofaceOrderEntity::getOrderStatus, FacetofaceOrderStatus.CLOSED.getValue())
|
|
|
|
|
+ .orderByDesc(FacetofaceOrderEntity::getId)
|
|
|
|
|
+ .last("LIMIT 1"));
|
|
|
|
|
+ if (active != null) {
|
|
|
|
|
+ throw new BusinessException(400, "该企业已有进行中的当面付申请");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- AlipayOpenAgentCreateRequest createRequest = new AlipayOpenAgentCreateRequest();
|
|
|
|
|
- createRequest.setBizModel(createModel);
|
|
|
|
|
|
|
+ // 查询同一企业是否有历史 CLOSED 申请单(用于复用更新而非插新行)
|
|
|
|
|
+ FacetofaceOrderEntity closedOrder = mapper.selectOne(
|
|
|
|
|
+ new LambdaQueryWrapper<FacetofaceOrderEntity>()
|
|
|
|
|
+ .eq(FacetofaceOrderEntity::getEnterpriseId, dto.getEnterpriseId())
|
|
|
|
|
+ .eq(FacetofaceOrderEntity::getOrderStatus, FacetofaceOrderStatus.CLOSED.getValue())
|
|
|
|
|
+ .orderByDesc(FacetofaceOrderEntity::getId)
|
|
|
|
|
+ .last("LIMIT 1"));
|
|
|
|
|
|
|
|
- AlipayOpenAgentCreateResponse createResponse = alipayClientFactory.getClient(dto.getEnterpriseId()).execute(createRequest);
|
|
|
|
|
- if (!createResponse.isSuccess())
|
|
|
|
|
- throw new BusinessException(400, "创建应用事务失败: " +
|
|
|
|
|
- (createResponse.getSubMsg() != null ? createResponse.getSubMsg() : createResponse.getMsg()));
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ // Step 1: 创建应用事务
|
|
|
|
|
+ AlipayOpenAgentCreateModel createModel = new AlipayOpenAgentCreateModel();
|
|
|
|
|
+ createModel.setAccount(dto.getAccount());
|
|
|
|
|
+ ContactModel contactInfo = new ContactModel();
|
|
|
|
|
+ contactInfo.setContactName(dto.getContactName());
|
|
|
|
|
+ contactInfo.setContactMobile(dto.getContactMobile());
|
|
|
|
|
+ if (StrUtil.isNotBlank(dto.getContactEmail())) {
|
|
|
|
|
+ contactInfo.setContactEmail(dto.getContactEmail());
|
|
|
|
|
+ }
|
|
|
|
|
+ createModel.setContactInfo(contactInfo);
|
|
|
|
|
+ if (StrUtil.isNotBlank(dto.getOrderTicket())) {
|
|
|
|
|
+ createModel.setOrderTicket(dto.getOrderTicket());
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- String batchNo = createResponse.getBatchNo();
|
|
|
|
|
- if (StrUtil.isBlank(batchNo))
|
|
|
|
|
- throw new BusinessException(400, "创建应用事务失败: 未返回 batch_no");
|
|
|
|
|
|
|
+ AlipayOpenAgentCreateRequest createRequest = new AlipayOpenAgentCreateRequest();
|
|
|
|
|
+ createRequest.setBizModel(createModel);
|
|
|
|
|
|
|
|
- log.info("当面付代开通 - Step1 创建事务成功: batch_no={}, account={}", batchNo, dto.getAccount());
|
|
|
|
|
|
|
+ AlipayOpenAgentCreateResponse createResponse = alipayClientFactory.getClient(dto.getEnterpriseId()).execute(createRequest);
|
|
|
|
|
+ if (!createResponse.isSuccess())
|
|
|
|
|
+ throw new BusinessException(400, "创建应用事务失败: " +
|
|
|
|
|
+ (createResponse.getSubMsg() != null ? createResponse.getSubMsg() : createResponse.getMsg()));
|
|
|
|
|
|
|
|
- // Step 2: 提交当面付签约申请
|
|
|
|
|
- AlipayOpenAgentFacetofaceSignRequest signRequest = new AlipayOpenAgentFacetofaceSignRequest();
|
|
|
|
|
- signRequest.setBatchNo(batchNo);
|
|
|
|
|
- if (dto.getSignAndAuth() != null) {
|
|
|
|
|
- signRequest.setSignAndAuth(dto.getSignAndAuth());
|
|
|
|
|
- }
|
|
|
|
|
- if (StrUtil.isNotBlank(dto.getRate())) {
|
|
|
|
|
- signRequest.setRate(dto.getRate());
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ String batchNo = createResponse.getBatchNo();
|
|
|
|
|
+ if (StrUtil.isBlank(batchNo))
|
|
|
|
|
+ throw new BusinessException(400, "创建应用事务失败: 未返回 batch_no");
|
|
|
|
|
|
|
|
- AlipayOpenAgentFacetofaceSignResponse signResponse = alipayClientFactory.getClient(dto.getEnterpriseId()).execute(signRequest);
|
|
|
|
|
- if (!signResponse.isSuccess())
|
|
|
|
|
- throw new BusinessException(400, "提交当面付签约失败: " +
|
|
|
|
|
- (signResponse.getSubMsg() != null ? signResponse.getSubMsg() : signResponse.getMsg()));
|
|
|
|
|
-
|
|
|
|
|
- log.info("当面付代开通 - Step2 签约成功: batch_no={}", batchNo);
|
|
|
|
|
-
|
|
|
|
|
- // Step 3: 确认提交事务
|
|
|
|
|
- AlipayOpenAgentConfirmModel confirmModel = new AlipayOpenAgentConfirmModel();
|
|
|
|
|
- confirmModel.setBatchNo(batchNo);
|
|
|
|
|
- AlipayOpenAgentConfirmRequest confirmRequest = new AlipayOpenAgentConfirmRequest();
|
|
|
|
|
- confirmRequest.setBizModel(confirmModel);
|
|
|
|
|
-
|
|
|
|
|
- AlipayOpenAgentConfirmResponse confirmResponse = alipayClientFactory.getClient(dto.getEnterpriseId()).execute(confirmRequest);
|
|
|
|
|
- if (!confirmResponse.isSuccess())
|
|
|
|
|
- throw new BusinessException(400, "确认提交事务失败: " +
|
|
|
|
|
- (confirmResponse.getSubMsg() != null ? confirmResponse.getSubMsg() : confirmResponse.getMsg()));
|
|
|
|
|
-
|
|
|
|
|
- log.info("当面付代开通 - Step3 确认事务成功: batch_no={}, order_no={}", batchNo, confirmResponse.getOrderNo());
|
|
|
|
|
-
|
|
|
|
|
- // 保存/更新申请单(对应 Python: 若存在已关闭旧单则复用更新)
|
|
|
|
|
- OffsetDateTime now = OffsetDateTime.now();
|
|
|
|
|
- if (closedOrder != null) {
|
|
|
|
|
- // 复用已关闭的旧单:设置字段后 update(避免 enterprise_id 唯一键冲突)
|
|
|
|
|
- BeanUtil.copyProperties(dto, closedOrder, "id");
|
|
|
|
|
- closedOrder.setOrderStatus(FacetofaceOrderStatus.SUBMITTED.getValue());
|
|
|
|
|
- closedOrder.setBatchNo(batchNo);
|
|
|
|
|
- closedOrder.setOrderNo(confirmResponse.getOrderNo());
|
|
|
|
|
- closedOrder.setAppAuthToken(confirmResponse.getAppAuthToken());
|
|
|
|
|
- closedOrder.setAppRefreshToken(confirmResponse.getAppRefreshToken());
|
|
|
|
|
- closedOrder.setAuthAppId(confirmResponse.getAuthAppId());
|
|
|
|
|
- closedOrder.setUserId(confirmResponse.getUserId());
|
|
|
|
|
- closedOrder.setOpenId(confirmResponse.getOpenId());
|
|
|
|
|
- closedOrder.setExpiresIn(confirmResponse.getExpiresIn());
|
|
|
|
|
- closedOrder.setReExpiresIn(confirmResponse.getReExpiresIn());
|
|
|
|
|
- closedOrder.setNextQueryTime(now.plusMinutes(5));
|
|
|
|
|
- closedOrder.setQueryCount(0);
|
|
|
|
|
- closedOrder.setLastQueryTime(null);
|
|
|
|
|
- closedOrder.setRejectReason(null);
|
|
|
|
|
- mapper.updateById(closedOrder);
|
|
|
|
|
- return BeanUtil.copyProperties(mapper.selectById(closedOrder.getId()), F2fOrderVO.class);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ log.info("当面付代开通 - Step1 创建事务成功: batch_no={}, account={}", batchNo, dto.getAccount());
|
|
|
|
|
|
|
|
- FacetofaceOrderEntity e = BeanUtil.copyProperties(dto, FacetofaceOrderEntity.class);
|
|
|
|
|
- e.setOrderStatus(FacetofaceOrderStatus.SUBMITTED.getValue());
|
|
|
|
|
- e.setBatchNo(batchNo);
|
|
|
|
|
- e.setOrderNo(confirmResponse.getOrderNo());
|
|
|
|
|
- e.setAppAuthToken(confirmResponse.getAppAuthToken());
|
|
|
|
|
- e.setAppRefreshToken(confirmResponse.getAppRefreshToken());
|
|
|
|
|
- e.setAuthAppId(confirmResponse.getAuthAppId());
|
|
|
|
|
- e.setUserId(confirmResponse.getUserId());
|
|
|
|
|
- e.setOpenId(confirmResponse.getOpenId());
|
|
|
|
|
- e.setExpiresIn(confirmResponse.getExpiresIn());
|
|
|
|
|
- e.setReExpiresIn(confirmResponse.getReExpiresIn());
|
|
|
|
|
- e.setNextQueryTime(now.plusMinutes(5));
|
|
|
|
|
- e.setQueryCount(0);
|
|
|
|
|
- mapper.insert(e);
|
|
|
|
|
|
|
+ // Step 2: 提交当面付签约申请
|
|
|
|
|
+ AlipayOpenAgentFacetofaceSignRequest signRequest = new AlipayOpenAgentFacetofaceSignRequest();
|
|
|
|
|
+ signRequest.setBatchNo(batchNo);
|
|
|
|
|
+ if (dto.getSignAndAuth() != null) {
|
|
|
|
|
+ signRequest.setSignAndAuth(dto.getSignAndAuth());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (StrUtil.isNotBlank(dto.getRate())) {
|
|
|
|
|
+ signRequest.setRate(dto.getRate());
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- return BeanUtil.copyProperties(mapper.selectById(e.getId()), F2fOrderVO.class);
|
|
|
|
|
|
|
+ AlipayOpenAgentFacetofaceSignResponse signResponse = alipayClientFactory.getClient(dto.getEnterpriseId()).execute(signRequest);
|
|
|
|
|
+ if (!signResponse.isSuccess())
|
|
|
|
|
+ throw new BusinessException(400, "提交当面付签约失败: " +
|
|
|
|
|
+ (signResponse.getSubMsg() != null ? signResponse.getSubMsg() : signResponse.getMsg()));
|
|
|
|
|
|
|
|
- } catch (AlipayApiException ex) {
|
|
|
|
|
- throw new BusinessException(400, "当面付代开通失败: " + ex.getMessage());
|
|
|
|
|
|
|
+ log.info("当面付代开通 - Step2 签约成功: batch_no={}", batchNo);
|
|
|
|
|
+
|
|
|
|
|
+ // Step 3: 确认提交事务
|
|
|
|
|
+ AlipayOpenAgentConfirmModel confirmModel = new AlipayOpenAgentConfirmModel();
|
|
|
|
|
+ confirmModel.setBatchNo(batchNo);
|
|
|
|
|
+ AlipayOpenAgentConfirmRequest confirmRequest = new AlipayOpenAgentConfirmRequest();
|
|
|
|
|
+ confirmRequest.setBizModel(confirmModel);
|
|
|
|
|
+
|
|
|
|
|
+ AlipayOpenAgentConfirmResponse confirmResponse = alipayClientFactory.getClient(dto.getEnterpriseId()).execute(confirmRequest);
|
|
|
|
|
+ if (!confirmResponse.isSuccess())
|
|
|
|
|
+ throw new BusinessException(400, "确认提交事务失败: " +
|
|
|
|
|
+ (confirmResponse.getSubMsg() != null ? confirmResponse.getSubMsg() : confirmResponse.getMsg()));
|
|
|
|
|
+
|
|
|
|
|
+ log.info("当面付代开通 - Step3 确认事务成功: batch_no={}, order_no={}", batchNo, confirmResponse.getOrderNo());
|
|
|
|
|
+
|
|
|
|
|
+ // 保存/更新申请单(对应 Python: 若存在已关闭旧单则复用更新)
|
|
|
|
|
+ OffsetDateTime now = OffsetDateTime.now();
|
|
|
|
|
+ if (closedOrder != null) {
|
|
|
|
|
+ // 复用已关闭的旧单:忽略 null 值避免覆盖已有数据
|
|
|
|
|
+ BeanUtil.copyProperties(dto, closedOrder, CopyOptions.create().setIgnoreNullValue(true));
|
|
|
|
|
+ closedOrder.setOrderStatus(FacetofaceOrderStatus.SUBMITTED.getValue());
|
|
|
|
|
+ closedOrder.setBatchNo(batchNo);
|
|
|
|
|
+ closedOrder.setOrderNo(confirmResponse.getOrderNo());
|
|
|
|
|
+ closedOrder.setAppAuthToken(confirmResponse.getAppAuthToken());
|
|
|
|
|
+ closedOrder.setAppRefreshToken(confirmResponse.getAppRefreshToken());
|
|
|
|
|
+ closedOrder.setAuthAppId(confirmResponse.getAuthAppId());
|
|
|
|
|
+ closedOrder.setUserId(confirmResponse.getUserId());
|
|
|
|
|
+ closedOrder.setOpenId(confirmResponse.getOpenId());
|
|
|
|
|
+ closedOrder.setExpiresIn(confirmResponse.getExpiresIn());
|
|
|
|
|
+ closedOrder.setReExpiresIn(confirmResponse.getReExpiresIn());
|
|
|
|
|
+ closedOrder.setNextQueryTime(now.plusMinutes(5));
|
|
|
|
|
+ closedOrder.setQueryCount(0);
|
|
|
|
|
+ closedOrder.setLastQueryTime(null);
|
|
|
|
|
+ closedOrder.setRejectReason(null);
|
|
|
|
|
+ mapper.updateById(closedOrder);
|
|
|
|
|
+ return BeanUtil.copyProperties(mapper.selectById(closedOrder.getId()), F2fOrderVO.class);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ FacetofaceOrderEntity e = BeanUtil.copyProperties(dto, FacetofaceOrderEntity.class);
|
|
|
|
|
+ e.setOrderStatus(FacetofaceOrderStatus.SUBMITTED.getValue());
|
|
|
|
|
+ e.setBatchNo(batchNo);
|
|
|
|
|
+ e.setOrderNo(confirmResponse.getOrderNo());
|
|
|
|
|
+ e.setAppAuthToken(confirmResponse.getAppAuthToken());
|
|
|
|
|
+ e.setAppRefreshToken(confirmResponse.getAppRefreshToken());
|
|
|
|
|
+ e.setAuthAppId(confirmResponse.getAuthAppId());
|
|
|
|
|
+ e.setUserId(confirmResponse.getUserId());
|
|
|
|
|
+ e.setOpenId(confirmResponse.getOpenId());
|
|
|
|
|
+ e.setExpiresIn(confirmResponse.getExpiresIn());
|
|
|
|
|
+ e.setReExpiresIn(confirmResponse.getReExpiresIn());
|
|
|
|
|
+ e.setNextQueryTime(now.plusMinutes(5));
|
|
|
|
|
+ e.setQueryCount(0);
|
|
|
|
|
+ mapper.insert(e);
|
|
|
|
|
+
|
|
|
|
|
+ return BeanUtil.copyProperties(mapper.selectById(e.getId()), F2fOrderVO.class);
|
|
|
|
|
+
|
|
|
|
|
+ } catch (AlipayApiException ex) {
|
|
|
|
|
+ throw new BusinessException(400, "当面付代开通失败: " + ex.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ } finally {
|
|
|
|
|
+ redisLockUtil.unlock(lockKey, lockValue);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 查询申请单状态 — 调用支付宝接口查询最新状态(对应 Python query_order_service)
|
|
* 查询申请单状态 — 调用支付宝接口查询最新状态(对应 Python query_order_service)
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 注意:不标注 @Transactional,仅在 DB 写入时使用事务,避免 HTTP 调用期间占用连接。
|
|
|
*/
|
|
*/
|
|
|
- @Transactional
|
|
|
|
|
public F2fOrderVO queryStatus(Long orderId) {
|
|
public F2fOrderVO queryStatus(Long orderId) {
|
|
|
FacetofaceOrderEntity e = requireOrder(orderId);
|
|
FacetofaceOrderEntity e = requireOrder(orderId);
|
|
|
|
|
|
|
@@ -217,6 +233,18 @@ public class FacetofaceService {
|
|
|
return BeanUtil.copyProperties(e, F2fOrderVO.class);
|
|
return BeanUtil.copyProperties(e, F2fOrderVO.class);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // 超过最大轮询次数自动关闭,防止未知状态永久卡住
|
|
|
|
|
+ int currentCount = e.getQueryCount() != null ? e.getQueryCount() : 0;
|
|
|
|
|
+ if (currentCount >= MAX_QUERY_COUNT) {
|
|
|
|
|
+ log.warn("当面付申请单超过最大轮询次数({}),自动关闭: batch_no={}, order_status={}",
|
|
|
|
|
+ MAX_QUERY_COUNT, e.getBatchNo(), e.getOrderStatus());
|
|
|
|
|
+ e.setOrderStatus(FacetofaceOrderStatus.CLOSED.getValue());
|
|
|
|
|
+ e.setNextQueryTime(null);
|
|
|
|
|
+ e.setRejectReason("超过最大轮询次数自动关闭");
|
|
|
|
|
+ doUpdateStatus(e);
|
|
|
|
|
+ return BeanUtil.copyProperties(mapper.selectById(e.getId()), F2fOrderVO.class);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (StrUtil.isBlank(e.getBatchNo())) {
|
|
if (StrUtil.isBlank(e.getBatchNo())) {
|
|
|
throw new BusinessException(400, "申请单无事务编号,无法查询");
|
|
throw new BusinessException(400, "申请单无事务编号,无法查询");
|
|
|
}
|
|
}
|
|
@@ -267,8 +295,10 @@ public class FacetofaceService {
|
|
|
e.setOrderStatus(FacetofaceOrderStatus.CLOSED.getValue());
|
|
e.setOrderStatus(FacetofaceOrderStatus.CLOSED.getValue());
|
|
|
e.setNextQueryTime(null);
|
|
e.setNextQueryTime(null);
|
|
|
break;
|
|
break;
|
|
|
- case "MERCHANT_INFO_HOLD":
|
|
|
|
|
default:
|
|
default:
|
|
|
|
|
+ // 未知状态:不更新 orderStatus,仅设置下次轮询时间
|
|
|
|
|
+ log.warn("当面付申请单遇到未知支付宝状态: batch_no={}, alipay_status={}, query_count={}",
|
|
|
|
|
+ e.getBatchNo(), alipayStatus, currentCount + 1);
|
|
|
e.setNextQueryTime(now.plusHours(4));
|
|
e.setNextQueryTime(now.plusHours(4));
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
@@ -277,26 +307,33 @@ public class FacetofaceService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
e.setLastQueryTime(now);
|
|
e.setLastQueryTime(now);
|
|
|
- e.setQueryCount(e.getQueryCount() != null ? e.getQueryCount() + 1 : 1);
|
|
|
|
|
- mapper.updateById(e);
|
|
|
|
|
|
|
+ e.setQueryCount(currentCount + 1);
|
|
|
|
|
+ doUpdateStatus(e);
|
|
|
} else {
|
|
} else {
|
|
|
log.warn("查询当面付申请单失败: batch_no={}, code={}, msg={}",
|
|
log.warn("查询当面付申请单失败: batch_no={}, code={}, msg={}",
|
|
|
e.getBatchNo(), queryResponse.getCode(), queryResponse.getSubMsg());
|
|
e.getBatchNo(), queryResponse.getCode(), queryResponse.getSubMsg());
|
|
|
}
|
|
}
|
|
|
} catch (AlipayApiException ex) {
|
|
} catch (AlipayApiException ex) {
|
|
|
log.error("查询当面付申请单异常: batch_no={}, error={}", e.getBatchNo(), ex.getMessage());
|
|
log.error("查询当面付申请单异常: batch_no={}, error={}", e.getBatchNo(), ex.getMessage());
|
|
|
|
|
+ // 手动查询失败时抛异常,让调用方感知
|
|
|
|
|
+ throw new BusinessException(400, "查询当面付申请单失败: " + ex.getMessage());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return BeanUtil.copyProperties(mapper.selectById(e.getId()), F2fOrderVO.class);
|
|
return BeanUtil.copyProperties(mapper.selectById(e.getId()), F2fOrderVO.class);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ void doUpdateStatus(FacetofaceOrderEntity e) {
|
|
|
|
|
+ mapper.updateById(e);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Transactional
|
|
@Transactional
|
|
|
public F2fOrderVO update(F2fOrderUpdateDTO dto) {
|
|
public F2fOrderVO update(F2fOrderUpdateDTO dto) {
|
|
|
FacetofaceOrderEntity exist = requireOrder(dto.getId());
|
|
FacetofaceOrderEntity exist = requireOrder(dto.getId());
|
|
|
if (dto.getOrderStatus() != null && !dto.getOrderStatus().equals(exist.getOrderStatus())) {
|
|
if (dto.getOrderStatus() != null && !dto.getOrderStatus().equals(exist.getOrderStatus())) {
|
|
|
validateStatusTransition(exist.getOrderStatus(), dto.getOrderStatus());
|
|
validateStatusTransition(exist.getOrderStatus(), dto.getOrderStatus());
|
|
|
}
|
|
}
|
|
|
- BeanUtil.copyProperties(dto, exist, "id");
|
|
|
|
|
|
|
+ BeanUtil.copyProperties(dto, exist, CopyOptions.create().setIgnoreNullValue(true));
|
|
|
mapper.updateById(exist);
|
|
mapper.updateById(exist);
|
|
|
return BeanUtil.copyProperties(mapper.selectById(dto.getId()), F2fOrderVO.class);
|
|
return BeanUtil.copyProperties(mapper.selectById(dto.getId()), F2fOrderVO.class);
|
|
|
}
|
|
}
|
|
@@ -312,13 +349,15 @@ public class FacetofaceService {
|
|
|
public List<FacetofaceOrderEntity> getPendingOrders() {
|
|
public List<FacetofaceOrderEntity> getPendingOrders() {
|
|
|
// 对应 Python: filter order_status IN (SUBMITTED, MERCHANT_AUDITING, MERCHANT_CONFIRM)
|
|
// 对应 Python: filter order_status IN (SUBMITTED, MERCHANT_AUDITING, MERCHANT_CONFIRM)
|
|
|
// AND next_query_time <= now
|
|
// AND next_query_time <= now
|
|
|
|
|
+ // LIMIT 100 防止待轮询订单过多时 OOM
|
|
|
return mapper.selectList(
|
|
return mapper.selectList(
|
|
|
new LambdaQueryWrapper<FacetofaceOrderEntity>()
|
|
new LambdaQueryWrapper<FacetofaceOrderEntity>()
|
|
|
.le(FacetofaceOrderEntity::getNextQueryTime, OffsetDateTime.now())
|
|
.le(FacetofaceOrderEntity::getNextQueryTime, OffsetDateTime.now())
|
|
|
.in(FacetofaceOrderEntity::getOrderStatus,
|
|
.in(FacetofaceOrderEntity::getOrderStatus,
|
|
|
FacetofaceOrderStatus.SUBMITTED.getValue(),
|
|
FacetofaceOrderStatus.SUBMITTED.getValue(),
|
|
|
FacetofaceOrderStatus.MERCHANT_AUDITING.getValue(),
|
|
FacetofaceOrderStatus.MERCHANT_AUDITING.getValue(),
|
|
|
- FacetofaceOrderStatus.MERCHANT_CONFIRM.getValue()));
|
|
|
|
|
|
|
+ FacetofaceOrderStatus.MERCHANT_CONFIRM.getValue())
|
|
|
|
|
+ .last("LIMIT 100"));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ========== private ==========
|
|
// ========== private ==========
|