diff --git a/sql/ruoyi-vue-pro.sql b/sql/ruoyi-vue-pro.sql index 1c7bd20ce8..f3a4b75539 100644 --- a/sql/ruoyi-vue-pro.sql +++ b/sql/ruoyi-vue-pro.sql @@ -982,6 +982,7 @@ CREATE TABLE `pay_channel` ( -- ---------------------------- BEGIN; INSERT INTO `pay_channel` VALUES (9, 'wx_pub', 0, NULL, 1, 1, 6, '{\"@class\":\"cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig\",\"appId\":\"wx041349c6f39b268b\",\"mchId\":\"1545083881\",\"apiVersion\":\"v2\",\"mchKey\":\"0alL64UDQdlCwiKZ73ib7ypaIjMns06p\",\"privateKeyContent\":\"-----BEGIN PRIVATE KEY-----\\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5q2hYE3loOQoH\\nl/2kh/epuj17W8VpV5vBl7ysJWAbBXux6mlq4gKTHD0QUQdiKtDEUm/bKC9Bi6VU\\nuklM5Y8oCaCbhjklHRbET8jsgd9phSNGviHclYRLsQRO8oXnN89kN0y7DYKm0hYd\\nmaiS12Z3v8VaImSTr4HVeHlC/z3S6mdwSr263stKt931YTcbTj/QFH7znsv9Na0u\\nX6LaMBEEAsJctWdm8Ndrd1tGh9Fzf0DA5VRXsJR3kkWspy+IwiDTPV/FDKOU9NJC\\nSxMmDePerTfkoZ2s1rltqBK0ykDJrXtxR+hTzEsKZ/KpNi8tyYpfNZsviHIlUsLP\\nFJ5UvUhpAgMBAAECggEAd90NltazqTIxpGdeCwrwOzWNnYbIclJprlhMKIJUgf1P\\nNrPTbHoOGXTAgzkcYCat8iAaMEzH/TOu/3zn92m3uqxEcEL9v1UBLqknWHAbkB6w\\ngGocqDAqYUcdNe5hvbyM+fCta5C0SQgV2PQrHOlMMICwYpkTfzhtxCdreXIYMoGg\\nJEIRkZWgrm/N7LTtNgizznuUjy6OURWjXaWKPcs3b3j6G1gLj9Vp++z4y0u51nqM\\n4R6fcvl8M6BjlcC8zo6DbOvCW8cXtuXsnru+2TPrUnsGeybJok4fEQsfW1BvpvPo\\nief38rYJn4OWxIrHcpWrhNtXtgRPeiMGFfIsEQDmVQKBgQDzXK6Nn3Nr3TFfGVTy\\n8QYrzOuY2NqzH8nnsLL6qn3HoKxTv+PcFKOTPsi6f4hIYCzBP0esRrPv0ffMu9oQ\\nJvFtCJvMmcKGtp0Q5hcj0y/XkbC3AWuahJtBv8lhKXVnQXSL0j3+ombljw4/8yN0\\nAzgBz+j/skQQgZ3sN5h+DHGtgwKBgQDDT784/2pd4m86c/uBmrwYfqu6MJo0eHJh\\n1XPtE+u8pOHyNTFk77rKobKDqN5VlrF0uEmBc/08LKhyxJ3vh/zAbcmqT1Mq778y\\nAKKUtVmvcaVDrvSQHsnhj0zt4SHGmmU34U2b9hV+nocq5VszX6/jp//HJi9bs3We\\ndAzfFCmaowKBgC1MmDVGc+6lCraf+X8LPFHU4Bnga70h8qxM6NPd/nG1R76DHn/t\\n25DiA+0rJgwK0unZxJadxoqic9TJNssA5Lmd+5o3GM2Imm311mLVwbcHqHQ4MHZf\\nrqKrd2m9lNv2hCIurVmDk1Gxsj5XHMdQfhFgSQengCHubp30r07vNA3PAoGAUEAE\\nIjdQTSMs8KeXP7mEb8wcY3R05/pVhT1fVJpK0kgtTofss7yM05V88/v+3sv8Pik6\\niqZN9tuimwWOn00Q3UA/DGtrkMjRlooMQ24AW8YmUZkhg9YivTtUMKnAZwopbLx2\\nVw7V5iDdCRMUVheK/c+ZmQpnixZBzcmBQGfYcGECgYBjEq3Mem+Aw6pXOu6+0FwH\\n9y6Xi4HhBkq0OOZZuXFtWVry7YrD3pBgzWVAZJqJCkyPKKZzCzwdbFd3u0lYBs35\\nzYgx7ug4hR+wfI980a3vxjcWGOqnOUUnUJ7ucIa+KDgnYV/bBy4jqpVreXmWAJXl\\nfyjG3eLWBrtrsI9YX6zeAA==\\n-----END PRIVATE KEY-----\\n\",\"privateCertContent\":\"-----BEGIN CERTIFICATE-----\\nMIID6TCCAtGgAwIBAgIUNkEHq6aQcF80NSYqWS58ybsJzI4wDQYJKoZIhvcNAQEL\\nBQAwXjELMAkGA1UEBhMCQ04xEzARBgNVBAoTClRlbnBheS5jb20xHTAbBgNVBAsT\\nFFRlbnBheS5jb20gQ0EgQ2VudGVyMRswGQYDVQQDExJUZW5wYXkuY29tIFJvb3Qg\\nQ0EwHhcNMjExMDIxMDU0NTQxWhcNMjYxMDIwMDU0NTQxWjB7MRMwEQYDVQQDDAox\\nNTQ1MDgzODgxMRswGQYDVQQKDBLlvq7kv6HllYbmiLfns7vnu58xJzAlBgNVBAsM\\nHuWOhuWfjuWMuuWkp+adjuWwp+aXpeeUqOWTgeW6lzELMAkGA1UEBgwCQ04xETAP\\nBgNVBAcMCFNoZW5aaGVuMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\\nuatoWBN5aDkKB5f9pIf3qbo9e1vFaVebwZe8rCVgGwV7seppauICkxw9EFEHYirQ\\nxFJv2ygvQYulVLpJTOWPKAmgm4Y5JR0WxE/I7IHfaYUjRr4h3JWES7EETvKF5zfP\\nZDdMuw2CptIWHZmoktdmd7/FWiJkk6+B1Xh5Qv890upncEq9ut7LSrfd9WE3G04/\\n0BR+857L/TWtLl+i2jARBALCXLVnZvDXa3dbRofRc39AwOVUV7CUd5JFrKcviMIg\\n0z1fxQyjlPTSQksTJg3j3q035KGdrNa5bagStMpAya17cUfoU8xLCmfyqTYvLcmK\\nXzWbL4hyJVLCzxSeVL1IaQIDAQABo4GBMH8wCQYDVR0TBAIwADALBgNVHQ8EBAMC\\nBPAwZQYDVR0fBF4wXDBaoFigVoZUaHR0cDovL2V2Y2EuaXRydXMuY29tLmNuL3B1\\nYmxpYy9pdHJ1c2NybD9DQT0xQkQ0MjIwRTUwREJDMDRCMDZBRDM5NzU0OTg0NkMw\\nMUMzRThFQkQyMA0GCSqGSIb3DQEBCwUAA4IBAQBe7XgncAY/1PLbCsnMsYt11k3V\\n2cdNZ+yuCxhlOEKk3nHE6WCTL6zL0qWlTKKpnw1rE/+4OS76Tg72wWXcHfHDAOgt\\n9icp62cKx1WO3QweeZpSvLDmtdLgKKrqeIWh+rL8+ZhuAOxSkaRwcsMTWDaLeDOi\\n0pGeqvfG8WNhPxkkaSI8xbiTK641Yg9WT/Q4yfHS7Q6wg1dj9YQdo0dvVB0S2Nir\\nX9IK6PUaHDnQeFKDmKgLkDGLaKaiijEvC91wMEE6qB8b0eNhciaxq2YhGHcFmSRP\\nWUyc5CmBadt7wIOH5Z3bfuwWGxqxKjNw/baM/d+nk7hlDr01YL9c0g16B9MW\\n-----END CERTIFICATE-----\\n\",\"apiV3Key\":\"joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase\"}', NULL, '2021-10-23 17:12:10', NULL, '2021-10-23 17:12:10', b'0'); +INSERT INTO `pay_channel` VALUES (10, 'alipay_wap', 0, NULL, 1, 1, 6, '{\"@class\":\"cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig\",\"serverUrl\":\"https://openapi.alipaydev.com/gateway.do\",\"appId\":\"2021000118641792\",\"signType\":\"RSA2\",\"mode\":1,\"privateKey\":\"MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDV+VmQ1FiAG1IOESPpZjDFYqkFptjck3KS8uTKk/QItz8KAKcRhL6X8x2hmIiel9SIWuZjmrBO0sCHRwNpfvbNNeIcFCK7cNf/VXO4vTiokeFb5htuAeKkprWE0NTZYW0L5BIt1ogJxDRhUUQM2JWchJmbMLKl2RU7FSrmsLFwIHq85LueWGyF7zTLvurtEYWv1DflGf7cZqtW0JvWMR4PJVFdbIJ/5KgxQ5j/BJLKwapgfEZWvdsLO2AuQjCYv5yb/SvyRuUV48zAvLcIHaim/qHm5GmnZNynBeovzfBjTmVZrx0HI6S5B0yLOoRes4GBBCQpFXL8Ov9uowHHwpH9AgMBAAECggEAIQteCqDQfhA6DtQU0LGobIM9CRNoQEBBHHKIZMSOll3+TUQmiO0QJhU0iUUuLBfUia5IEC/OdI3Vj86mtz8VTEG7Bo0RhBL8OIFw2qHWQyosPG3/5HBEGRtpwvYhOOTz2zdAm3WbEq8LS9AqCzXTfRV5R18w563runEda/zzmhYRo8INr09G3HYLo83i3LPLAVMi+ndOqxtKamNc3hCehezo/34DleA2/1/giQLhqhzHzEM0KwYPmBRoij3/jnPSZFwe8sXS8PwVX9bmiXtIEluvzwMylsMqMcmL89reFRRiskbVAVV8zWqa/06wjqbSARNTTZYJa6LQ8sjsdGAJvQKBgQD0Ka0Zu77+axgy6AzXvLx0KaC+0iwobr2g8X5R07ZyqoBlPlLUcHC6nRRHIYhZLfEYBFfFpUj8osReKDWJ2euonevGFGr8OxmZe1BX+LPf+9hVWDhTmbD++ZSdgOQMJ9a4BJF4YHkYcCfWwYnsg8ZUlrmeh4+SbkgRp1x0xLswiwKBgQDgWP+YVxQz3AmRQmIAtZbqfiDzOntHJyrJC1tDEX3Q/dA6PopWUYaSqFJuGJYvUW1ycBl2skKYFlxVGQgUB3ZrhuumzINc24XSWMQoNpkewMG54qXfuSA57PzNXmHcvyLL2HQxISCD9yNJul6ecsGnPUWuaDLC16ZF/Q3ChrjQlwKBgGKCAgW02qz49k1rk+riicHwHZt/XjN94mHxrL5ExYJjyeOPDooJR2HzCABexgz83R2MewER222aGdHHNTqFwm9IL5y+Fh/nlD95IgQsIh5HFJPyQN9xzZhBh7U4EEnbNOUPasV/Xrv+XARoF0ZmL/lmykLsfH9eoRMGS+YMjV1bAoGAFttaZxXwG/x+CQufWn0lvAxPpRg/OReXd1Yt3R5qGCHT1itLAtJZiJWXmFnu6zE7ml4rafltaXtVuuHK/edovDnJxnutoodHEhAzI/m0DfsLgbnCtpFw5BXuB6pnBAuBKw2JgPvkCS3jrX5MZ44/hp9qewNosIsyCI1omnoJWE8CgYBUR1L5i1Z9sQdIw8E4MOzbc5uliTX2nJVG65bLc/+Cp3W3YoQw7RK8qiTv8XoOICMJXCBww2roM4HkbwJ3knQbbTiMyksRyLHvDuTg4UdH4pkNDxGsQND9sUd3bR5fayH0Z/QBohuLOFHP/C7WaHPwa4hZBKavibiWhmDtzdmOIw==\",\"alipayPublicKey\":\"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5w0ByG2xxiw///4NJiynTyjvZOX9Xb1p+A2TMJdOdwx1eWrYHv4mW7rvKfpxD5shZtU1lxzXLT3EGCAnW8f8SVDj+v+UAu3HEaKDgyqO6WA1ZLVSrCLPTb4u1C3ozbKaim88sl9+TxeaNUwuIpWshLDYoseMgRYp/VLUfpMNkueGKczkDkGH/4BY8lj/dsIItLqU9Px4PIpGCztm0vrg7mvH4XlSk5b5ui9uQ05AhS+PHTGrloY9AOrtjQTZmVebEUHf1pVmoofUr0q1TqhS9HQU1XIkxRnxOvmOcscH4rE2qMKajk4dR5rgnuNPRWSj24xwbNf3nSHDTAH7PDogwIDAQAB\",\"appCertContent\":null,\"alipayPublicCertContent\":null,\"rootCertContent\":null}', NULL, '2021-11-02 17:12:10', NULL, '2021-11-02 17:12:10', b'0'); COMMIT; -- ---------------------------- @@ -1250,7 +1251,7 @@ CREATE TABLE `pay_order_extension` ( `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户 IP', `status` tinyint NOT NULL COMMENT '支付状态', `channel_extras` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付渠道的额外参数', - `channel_notify_data` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付渠道异步通知的内容', + `channel_notify_data` varchar(2048) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付渠道异步通知的内容', `creator` varchar(64) DEFAULT '' COMMENT '创建者', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `updater` varchar(64) DEFAULT '' COMMENT '更新者', diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java index 002716eaca..a22100e761 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java @@ -1,9 +1,11 @@ package cn.iocoder.yudao.coreservice.modules.pay.service.order; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; + import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO; import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO; +import cn.iocoder.yudao.framework.pay.core.client.dto.NotifyDataDTO; import javax.validation.Valid; @@ -46,6 +48,6 @@ public interface PayOrderCoreService { * @param channelCode 渠道编码 * @param notifyData 通知数据 */ - void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception; + void notifyPayOrder(Long channelId, String channelCode, NotifyDataDTO notifyData) throws Exception; } diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java index 5515dd87ca..6a090828fd 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayOrderCoreServiceImpl.java @@ -18,6 +18,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreS import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService; import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreService; + import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderCreateReqDTO; import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO; import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO; @@ -26,6 +27,7 @@ import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.pay.config.PayProperties; import cn.iocoder.yudao.framework.pay.core.client.PayClient; import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.client.dto.NotifyDataDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import lombok.extern.slf4j.Slf4j; @@ -135,9 +137,11 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { // 调用三方接口 PayOrderUnifiedReqDTO unifiedOrderReqDTO = PayOrderCoreConvert.INSTANCE.convert2(reqDTO); // 商户相关字段 + //TODO jason @芋艿 是否加一个属性 如tradeNo 支付订单号, 用这个merchantOrderId让人迷糊 unifiedOrderReqDTO.setMerchantOrderId(orderExtension.getNo()) // 注意,此处使用的是 PayOrderExtensionDO.no 属性! .setSubject(order.getSubject()).setBody(order.getBody()) - .setNotifyUrl(genChannelPayNotifyUrl(channel)); + .setNotifyUrl(genChannelPayNotifyUrl(channel)) + .setReturnUrl(genChannelReturnUrl(channel)); // 订单相关字段 unifiedOrderReqDTO.setAmount(order.getAmount()).setExpireTime(order.getExpireTime()); CommonResult unifiedOrderResult = client.unifiedOrder(unifiedOrderReqDTO); @@ -149,6 +153,16 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { .setInvokeResponse(unifiedOrderResult.getData()); } + /** + * 根据支付渠道的编码,生成支付渠道的返回地址 + * @param channel + * @return + */ + private String genChannelReturnUrl(PayChannelDO channel) { + return payProperties.getReturnUrl() + "/" + StrUtil.replace(channel.getCode(), "_", "-") + + "/" + channel.getId(); + } + /** * 根据支付渠道的编码,生成支付渠道的回调地址 * @@ -181,9 +195,9 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @Override @Transactional - public void notifyPayOrder(Long channelId, String channelCode, String notifyData) throws Exception { + public void notifyPayOrder(Long channelId, String channelCode, NotifyDataDTO notifyData) throws Exception { // TODO 芋艿,记录回调日志 - log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData); + log.info("[notifyPayOrder][channelId({}) 回调数据({})]", channelId, notifyData.getOrigData()); // 校验支付渠道是否有效 PayChannelDO channel = payChannelCoreService.validPayChannel(channelId); @@ -193,6 +207,7 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); } + //TODO @jason 校验 是否支付宝调用。 使用 支付宝publickey 或者payclient 加一个校验方法 // 解析支付结果 PayOrderNotifyRespDTO notifyRespDTO = client.parseOrderNotify(notifyData); @@ -207,9 +222,10 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); } // 1.2 更新 PayOrderExtensionDO + //TODO @jason notifyRespDTO.getTradeStatus() 需要根据不同的状态更新成不同的值 PayOrderStatusEnum int updateCounts = payOrderExtensionCoreMapper.updateByIdAndStatus(orderExtension.getId(), PayOrderStatusEnum.WAITING.getStatus(), PayOrderExtensionDO.builder().id(orderExtension.getId()) - .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData).build()); + .status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(notifyData.getOrigData()).build()); if (updateCounts == 0) { // 校验状态,必须是待支付 throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING); } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java index c568684775..525ec876d1 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/PayProperties.java @@ -6,8 +6,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.NotEmpty; -import javax.validation.constraints.NotNull; -import java.time.Duration; @ConfigurationProperties(prefix = "yudao.pay") @Validated @@ -25,8 +23,15 @@ public class PayProperties { * 退款回调地址 * 注意点,同 {@link #payNotifyUrl} 属性 */ - @NotNull(message = "短信发送频率不能为空") + @NotEmpty(message = "短信发送频率不能为空") @URL(message = "退款回调地址的格式必须是 URL") private String refundNotifyUrl; + // TODO @jason:改成 payReturnUrl 。另外,可以加个 @NotEmpty,避免未填写 + /** + * 支付完成的返回地址 + */ + @URL(message = "支付返回的地址的格式必须是 URL") + private String returnUrl; + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java index 96a5233fc5..01f28cb310 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.framework.pay.core.client; +import cn.iocoder.yudao.framework.pay.core.client.dto.NotifyDataDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; @@ -32,6 +33,6 @@ public interface PayClient { * @return 解析结果 * @throws Exception 解析失败,抛出异常 */ - PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception; + PayOrderNotifyRespDTO parseOrderNotify(NotifyDataDTO data) throws Exception; } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/NotifyDataDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/NotifyDataDTO.java new file mode 100644 index 0000000000..c081c41682 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/NotifyDataDTO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.framework.pay.core.client.dto; + +import lombok.Builder; +import lombok.Data; +import lombok.ToString; + +import java.util.Map; + +// TODO @jason:NotifyDataDTO=》PayNotifyDataDTO。另外注释记得加起来哈 +@Data +@ToString +@Builder +public class NotifyDataDTO { + + // TODO @jason:这个字段,改成 body + private String origData; + // TODO @jason:这个字段如果暂时没用,可以去掉。 + //1:xml 2:form + private int format; + + //form 格式的 data; + private Map params; +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderNotifyRespDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderNotifyRespDTO.java index e9e3fb457c..54ff166086 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderNotifyRespDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderNotifyRespDTO.java @@ -42,4 +42,14 @@ public class PayOrderNotifyRespDTO { */ private String data; + + /** + * TODO @jason 结合其他的渠道定义成枚举, + * alipay + * TRADE_CLOSED,未付款交易超时关闭,或支付完成后全额退款。 + * TRADE_SUCCESS, 交易支付成功 + * TRADE_FINISHED 交易结束,不可退款。 + */ + private String tradeStatus; + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java index 299f0b3f15..6f99bb80d4 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayOrderUnifiedReqDTO.java @@ -44,11 +44,16 @@ public class PayOrderUnifiedReqDTO { @Length(max = 128, message = "商品描述信息长度不能超过128") private String body; /** - * 支付结果的回调地址 + * 支付结果的 notify 回调地址 */ @NotEmpty(message = "支付结果的回调地址不能为空") - @URL(message = "支付结果的回调地址必须是 URL 格式") + @URL(message = "支付结果的 notify 回调地址必须是 URL 格式") private String notifyUrl; + /** + * 支付结果的 return 回调地址 + */ + @URL(message = "支付结果的 return 回调地址必须是 URL 格式") + private String returnUrl; // ========== 订单相关字段 ========== diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayCodeMapping.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayCodeMapping.java index 8cafd425de..b44dcb6aad 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayCodeMapping.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayPayCodeMapping.java @@ -18,6 +18,10 @@ public class AlipayPayCodeMapping extends AbstractPayCodeMapping { if (Objects.equals(apiCode, "10000")) { return GlobalErrorCodeConstants.SUCCESS; } + // alipay wap api code 返回为null, 暂时定为-9999 + if(Objects.equals(apiCode, "-9999")){ // TODO @jason:空格要注意哈。if () { + return GlobalErrorCodeConstants.SUCCESS; + } return null; } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java index 9c0ec38065..5a97498132 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClient.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; import cn.hutool.core.bean.BeanUtil; import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.NotifyDataDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; @@ -68,7 +69,7 @@ public class AlipayQrPayClient extends AbstractPayClient } @Override - public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception { + public PayOrderNotifyRespDTO parseOrderNotify(NotifyDataDTO data) throws Exception { // TODO 芋艿:待完成 return null; } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java index 7f3bd5a913..a67e2a3178 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayWapPayClient.java @@ -1,7 +1,9 @@ package cn.iocoder.yudao.framework.pay.core.client.impl.alipay; import cn.hutool.core.bean.BeanUtil; +import cn.hutool.core.date.DateUtil; import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.NotifyDataDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; @@ -14,6 +16,9 @@ import com.alipay.api.request.AlipayTradeWapPayRequest; import com.alipay.api.response.AlipayTradeWapPayResponse; import lombok.SneakyThrows; +import java.util.Map; +import java.util.Objects; + /** * 支付宝【手机网站】的 PayClient 实现类 * 文档:https://opendocs.alipay.com/apis/api_1/alipay.trade.wap.pay @@ -45,12 +50,16 @@ public class AlipayWapPayClient extends AbstractPayClient model.setBody(reqDTO.getBody()); model.setTotalAmount(calculateAmount(reqDTO.getAmount()).toString()); model.setProductCode("QUICK_WAP_PAY"); // TODO 芋艿:这里咋整 - model.setSellerId("2088102147948060"); // TODO 芋艿:这里咋整 - // TODO 芋艿:userIp + expireTime + //TODO 芋艿:这里咋整 jason @芋艿 可以去掉吧, + // TODO @jason: 这个支付方式,需要有 sellerId 么? + //model.setSellerId("2088102147948060"); + model.setTimeExpire(DateUtil.format(reqDTO.getExpireTime(),"yyyy-MM-dd HH:mm:ss")); + // TODO 芋艿:userIp // 构建 AlipayTradeWapPayRequest AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest(); request.setBizModel(model); - + request.setNotifyUrl(reqDTO.getNotifyUrl()); + request.setReturnUrl(reqDTO.getReturnUrl()); // 执行请求 AlipayTradeWapPayResponse response; try { @@ -58,13 +67,31 @@ public class AlipayWapPayClient extends AbstractPayClient } catch (AlipayApiException e) { return PayCommonResult.build(e.getErrCode(), e.getErrMsg(), null, codeMapping); } -// TODO 芋艿:sub Code - return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping); + + // TODO 芋艿:sub Code + if(response.isSuccess() && Objects.isNull(response.getCode()) && Objects.nonNull(response.getBody())){ + //成功alipay wap 成功 code 为 null , body 为form 表单 + return PayCommonResult.build("-9999", "Success", response, codeMapping); + }else { + return PayCommonResult.build(response.getCode(), response.getMsg(), response, codeMapping); + } } + // TODO @jason: 注释记得补下哈 + /** + * //https://opendocs.alipay.com/open/203/105286 + * @param data 通知结果 + * @return + * @throws Exception + */ @Override - public PayOrderNotifyRespDTO parseOrderNotify(String data) throws Exception { - // TODO 芋艿:待完成 - return null; + public PayOrderNotifyRespDTO parseOrderNotify(NotifyDataDTO data) throws Exception { + Map params = data.getParams(); + return PayOrderNotifyRespDTO.builder().orderExtensionNo(params.get("out_trade_no")) + .channelOrderNo(params.get("trade_no")).channelUserId(params.get("seller_id")) + .tradeStatus(params.get("trade_status")) + .successTime(DateUtil.parse(params.get("notify_time"), "yyyy-MM-dd HH:mm:ss")) + .data(data.getOrigData()).build(); } + } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java index 03e63c9f43..c2b0635cbd 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/wx/WXPubPayClient.java @@ -8,6 +8,7 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.util.io.FileUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.pay.core.client.PayCommonResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.NotifyDataDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderNotifyRespDTO; import cn.iocoder.yudao.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; @@ -131,14 +132,14 @@ public class WXPubPayClient extends AbstractPayClient { } @Override - public PayOrderNotifyRespDTO parseOrderNotify(String data) throws WxPayException { - WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data); + public PayOrderNotifyRespDTO parseOrderNotify(NotifyDataDTO data) throws WxPayException { + WxPayOrderNotifyResult notifyResult = client.parseOrderNotifyResult(data.getOrigData()); Assert.isTrue(Objects.equals(notifyResult.getResultCode(), "SUCCESS"), "支付结果非 SUCCESS"); // 转换结果 return PayOrderNotifyRespDTO.builder().orderExtensionNo(notifyResult.getOutTradeNo()) .channelOrderNo(notifyResult.getTransactionId()).channelUserId(notifyResult.getOpenid()) .successTime(DateUtil.parse(notifyResult.getTimeEnd(), "yyyyMMddHHmmss")) - .data(data).build(); + .data(data.getOrigData()).build(); } } diff --git a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayOrderController.java b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayOrderController.java index 077904614e..cb882752ab 100644 --- a/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayOrderController.java +++ b/yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayOrderController.java @@ -6,17 +6,21 @@ import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreServic import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO; import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO; import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.pay.core.client.dto.NotifyDataDTO; import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitReqVO; import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitRespVO; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.MediaType; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; +import java.util.Map; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; @@ -54,7 +58,7 @@ public class PayOrderController { @ApiOperation("通知微信公众号支付的结果") public String notifyWxPayOrder(@PathVariable("channelId") Long channelId, @RequestBody String xmlData) throws Exception { - payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.WX_PUB.getCode(), xmlData); + payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.WX_PUB.getCode(), NotifyDataDTO.builder().origData(xmlData).build()); return "success"; } @@ -72,4 +76,28 @@ public class PayOrderController { return "success"; } + @PostMapping(value = "/notify/alipay-wap/{channelId}", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) + @ApiOperation("支付宝wap页面回调") + public String notifyAliPayWapPayOrder(@PathVariable("channelId") Long channelId, + @RequestParam Map params, + @RequestBody String originData) throws Exception { + //TODO @jason 校验 是否支付宝调用。 使用 支付宝publickey payclient 或许加一个校验方法 + payOrderCoreService.notifyPayOrder(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), NotifyDataDTO.builder().params(params).origData(originData).build()); + return "success"; + } + + // TODO @jason 如果有些字段不注释,可以删除哈。不然 IDEA 会报警 + /** + * https://opendocs.alipay.com/open/203/105285#%E5%89%8D%E5%8F%B0%E5%9B%9E%E8%B7%B3%E5%8F%82%E6%95%B0%E8%AF%B4%E6%98%8E + * @param channelId + * @return + * @throws Exception + */ + @GetMapping(value = "/return/alipay-wap/{channelId}") + @ApiOperation("支付宝wap页面回跳") + public String returnAliPayWapPayOrder(@PathVariable("channelId") Long channelId){ + //TODO @jason 校验 是否支付宝调用。 支付宝publickey 可以根据 appId 跳转不同的页面 + return "支付成功"; + } + } diff --git a/yudao-user-server/src/main/resources/application-local.yaml b/yudao-user-server/src/main/resources/application-local.yaml index ac20815c4b..ff0a29d965 100644 --- a/yudao-user-server/src/main/resources/application-local.yaml +++ b/yudao-user-server/src/main/resources/application-local.yaml @@ -153,5 +153,6 @@ yudao: - ${management.endpoints.web.base-path}/** # 不处理 Actuator 的请求 demo: false # 关闭演示模式 pay: - pay-notify-url: http://niubi.natapp1.cc/api/pay/order/notify - refund-notify-url: http://niubi.natapp1.cc/api/pay/refund/notify + pay-notify-url: http://jg6rde.natappfree.cc/api/pay/order/notify + refund-notify-url: http://jg6rde.natappfree.cc/api/pay/refund/notify + return-url: http://jg6rde.natappfree.cc/api/pay/order/return diff --git a/yudao-user-server/src/main/resources/static/pay_alipay_wap.html b/yudao-user-server/src/main/resources/static/pay_alipay_wap.html new file mode 100644 index 0000000000..5f48dfce46 --- /dev/null +++ b/yudao-user-server/src/main/resources/static/pay_alipay_wap.html @@ -0,0 +1,66 @@ + + + + + + 支付测试页 + + + +
点击如下按钮,发起支付的测试
+
+ +
+
+ + + diff --git a/yudao-user-server/src/main/resources/static/pay.html b/yudao-user-server/src/main/resources/static/pay_wx_pub.html similarity index 100% rename from yudao-user-server/src/main/resources/static/pay.html rename to yudao-user-server/src/main/resources/static/pay_wx_pub.html