mall + pay:

1. 修复支付宝沙箱地址的调整
2. 收银台的前端 URL 支付走整个网页跳转
3. 收银台的支付成功后,增加 returnUrl 回跳
4. 修复 PayNotifyTask 首次通知时,可能会失败的情况;原因:租户未传递;
This commit is contained in:
YunaiV
2023-07-12 00:04:19 +08:00
parent f1c4c7964a
commit 0ac599a3d9
9 changed files with 81 additions and 154 deletions

View File

@ -1,6 +1,6 @@
package cn.iocoder.yudao.module.pay.dal.dataobject.notify;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
@ -25,7 +25,7 @@ import java.time.LocalDateTime;
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
public class PayNotifyTaskDO extends BaseDO {
public class PayNotifyTaskDO extends TenantBaseDO {
/**
* 通知频率,单位为秒。

View File

@ -24,10 +24,11 @@ import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import javax.annotation.Resource;
import javax.validation.Valid;
@ -86,6 +87,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
private PayNotifyServiceImpl self;
@Override
@Transactional(rollbackFor = Exception.class)
public void createPayNotifyTask(PayNotifyTaskCreateReqDTO reqDTO) {
PayNotifyTaskDO task = new PayNotifyTaskDO();
task.setType(reqDTO.getType()).setDataId(reqDTO.getDataId());
@ -105,8 +107,13 @@ public class PayNotifyServiceImpl implements PayNotifyService {
// 执行插入
payNotifyTaskMapper.insert(task);
// 异步直接发起任务。虽然会有定时任务扫描,但是会导致延迟
self.executeNotifyAsync(task);
// 必须在事务提交后,在发起任务,否则 PayNotifyTaskDO 还没入库,就提前回调接入的业务
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void afterCommit() {
executeNotify(task);
}
});
}
@Override
@ -121,7 +128,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
CountDownLatch latch = new CountDownLatch(tasks.size());
tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> {
try {
executeNotifySync(task);
executeNotify(task);
} finally {
latch.countDown();
}
@ -150,22 +157,12 @@ public class PayNotifyServiceImpl implements PayNotifyService {
log.error("[awaitExecuteNotify][任务未处理完,总任务数({}) 剩余任务数({})]", size, latch.getCount());
}
/**
* 异步执行单个支付通知
*
* @param task 通知任务
*/
@Async
public void executeNotifyAsync(PayNotifyTaskDO task) {
self.executeNotifySync(task); // 使用 self避免事务不发起
}
/**
* 同步执行单个支付通知
*
* @param task 通知任务
*/
public void executeNotifySync(PayNotifyTaskDO task) {
public void executeNotify(PayNotifyTaskDO task) {
// 分布式锁,避免并发问题
payNotifyLockCoreRedisDAO.lock(task.getId(), NOTIFY_TIMEOUT_MILLIS, () -> {
// 校验,当前任务是否已经被通知过
@ -178,12 +175,12 @@ public class PayNotifyServiceImpl implements PayNotifyService {
}
// 执行通知
self.executeNotify(dbTask);
self.executeNotify0(dbTask);
});
}
@Transactional
public void executeNotify(PayNotifyTaskDO task) {
public void executeNotify0(PayNotifyTaskDO task) {
// 发起回调
CommonResult<?> invokeResult = null;
Throwable invokeException = null;
@ -223,7 +220,7 @@ public class PayNotifyServiceImpl implements PayNotifyService {
}
// 拼接 header 参数
Map<String, String> headers = new HashMap<>();
TenantUtils.addTenantHeader(headers);
TenantUtils.addTenantHeader(headers, task.getTenantId());
// 发起请求
try (HttpResponse response = HttpUtil.createPost(task.getNotifyUrl())

View File

@ -33,6 +33,8 @@ import static org.junit.jupiter.api.Assertions.*;
@Import({PayChannelServiceImpl.class})
public class PayChannelServiceTest extends BaseDbUnitTest {
private static final String ALIPAY_SERVER_URL = "https://openapi.alipay.com/gateway.do";
@Resource
private PayChannelServiceImpl channelService;
@ -106,7 +108,6 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
assertPojoEquals(reqVO, channel, "config");
// 关于config 对象应该拿出来重新对比
assertPojoEquals(payClientConfig, channel.getConfig());
}
@Test
@ -291,7 +292,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
public AlipayPayClientConfig getPublicKeyConfig() {
return new AlipayPayClientConfig()
.setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD)
.setServerUrl(ALIPAY_SERVER_URL)
.setAppId("APP00001")
.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
.setMode(AlipayPayClientConfig.MODE_PUBLIC_KEY)
@ -304,7 +305,7 @@ public class PayChannelServiceTest extends BaseDbUnitTest {
public AlipayPayClientConfig getCertificateConfig() {
return new AlipayPayClientConfig()
.setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD)
.setServerUrl(ALIPAY_SERVER_URL)
.setAppId("APP00001")
.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT)
.setMode(AlipayPayClientConfig.MODE_CERTIFICATE)