From 6dc65234ef8f71320c120b3e88b888da2de3d39a Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 23 Oct 2021 17:47:27 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=94=AF=E4=BB=98=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E8=A1=A8=E7=9A=84=20SQL=EF=BC=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=9A=84=E5=AE=9E=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sql/pay2.sql | 172 ++++++++++++++++++ .../service/sms/SysSmsChannelService.java | 2 +- .../convert/order/PayOrderCoreConvert.java | 3 + .../pay/dal/dataobject/merchant/PayAppDO.java | 14 +- .../dal/dataobject/merchant/PayChannelDO.java | 23 ++- .../dataobject/merchant/PayMerchantDO.java | 11 +- .../pay/dal/dataobject/order/PayOrderDO.java | 59 +++--- .../dataobject/order/PayOrderExtensionDO.java | 15 +- .../pay/dal/dataobject/order/PayRefundDO.java | 22 +-- .../mysql/merchant/PayChannelCoreMapper.java | 6 + ...ts.java => PayErrorCodeCoreConstants.java} | 7 +- .../merchant/PayChannelCoreService.java | 5 + .../merchant/impl/PayAppCoreServiceImpl.java | 2 +- .../impl/PayChannelCoreServiceImpl.java | 72 +++++++- .../order/dto/PayOrderCreateReqDTO.java | 8 +- .../order/dto/PayOrderSubmitReqDTO.java | 6 +- .../order/impl/PayOrderCoreServiceImpl.java | 21 ++- .../BaseDbAndRedisIntegrationTest.java | 38 ++++ .../coreservice/BaseDbIntegrationTest.java | 30 +++ .../coreservice/BaseRedisIntegrationTest.java | 23 +++ .../dataobject/merchant/PayChannelDOTest.java | 29 +++ .../merchant/PayChannelCoreMapperTest.java | 56 ++++++ .../application-integration-test.yaml | 92 ++++++++++ .../yudao-spring-boot-starter-biz-pay/pom.xml | 16 +- .../pay/config/YudaoPayAutoConfiguration.java | 21 +++ .../pay/core/client/PayClientConfig.java | 6 + .../client/dto/PayOrderUnifiedReqDTO.java | 6 +- .../client/impl/alipay/AlipayQrPayClient.java | 2 +- .../impl/alipay/AlipayWapPayClient.java | 2 +- 29 files changed, 664 insertions(+), 105 deletions(-) create mode 100644 sql/pay2.sql rename yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/{PayErrorCodeConstants.java => PayErrorCodeCoreConstants.java} (84%) create mode 100644 yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbAndRedisIntegrationTest.java create mode 100644 yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbIntegrationTest.java create mode 100644 yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseRedisIntegrationTest.java create mode 100644 yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDOTest.java create mode 100644 yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapperTest.java create mode 100644 yudao-core-service/src/test-integration/resources/application-integration-test.yaml create mode 100644 yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java diff --git a/sql/pay2.sql b/sql/pay2.sql new file mode 100644 index 000000000..b6cf2359a --- /dev/null +++ b/sql/pay2.sql @@ -0,0 +1,172 @@ +/* + Navicat Premium Data Transfer + + Source Server : 127.0.0.1 + Source Server Type : MySQL + Source Server Version : 80026 + Source Host : localhost:3306 + Source Schema : ruoyi-vue-pro + + Target Server Type : MySQL + Target Server Version : 80026 + File Encoding : 65001 + + Date: 23/10/2021 17:46:45 +*/ + +SET NAMES utf8mb4; +SET FOREIGN_KEY_CHECKS = 0; + +-- ---------------------------- +-- Table structure for pay_app +-- ---------------------------- +DROP TABLE IF EXISTS `pay_app`; +CREATE TABLE `pay_app` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '应用编号', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '应用名', + `status` tinyint NOT NULL COMMENT '开启状态', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + `pay_notify_url` varchar(1024) NOT NULL COMMENT '支付结果的回调地址', + `notify_notify_url` varchar(1024) NOT NULL COMMENT '退款结果的回调地址', + `merchant_id` bigint NOT NULL COMMENT '商户编号', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='支付应用信息'; + +-- ---------------------------- +-- Records of pay_app +-- ---------------------------- +BEGIN; +INSERT INTO `pay_app` VALUES (6, '芋道', 0, '我是一个公众号', 'http://127.0.0.1', 'http://127.0.0.1', 1, '', '2021-10-23 08:49:25', '', '2021-10-23 08:49:25', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for pay_channel +-- ---------------------------- +DROP TABLE IF EXISTS `pay_channel`; +CREATE TABLE `pay_channel` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '商户编号', + `code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道编码', + `status` tinyint NOT NULL COMMENT '开启状态', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + `fee_rate` double NOT NULL DEFAULT '0' COMMENT '渠道费率,单位:百分比', + `merchant_id` bigint NOT NULL COMMENT '商户编号', + `app_id` bigint NOT NULL COMMENT '应用编号', + `config` varchar(4096) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '支付渠道配置', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='支付渠道\n'; + +-- ---------------------------- +-- Records of 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'); +COMMIT; + +-- ---------------------------- +-- Table structure for pay_merchant +-- ---------------------------- +DROP TABLE IF EXISTS `pay_merchant`; +CREATE TABLE `pay_merchant` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '商户编号', + `no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商户号', + `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商户全称', + `short_name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商户简称', + `status` tinyint NOT NULL COMMENT '开启状态', + `remark` varchar(255) DEFAULT NULL COMMENT '备注', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='支付商户信息'; + +-- ---------------------------- +-- Records of pay_merchant +-- ---------------------------- +BEGIN; +INSERT INTO `pay_merchant` VALUES (1, 'M233666999', '芋道源码', '芋艿', 0, '我是备注', '', '2021-10-23 08:31:14', '', '2021-10-23 08:44:04', b'0'); +COMMIT; + +-- ---------------------------- +-- Table structure for pay_order +-- ---------------------------- +DROP TABLE IF EXISTS `pay_order`; +CREATE TABLE `pay_order` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '支付订单编号', + `merchant_id` bigint NOT NULL COMMENT '商户编号', + `app_id` bigint NOT NULL COMMENT '应用编号', + `channel_id` bigint NOT NULL COMMENT '渠道编号', + `channel_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道编码', + `merchant_order_id` varchar(64) NOT NULL COMMENT '商户订单编号', + `subject` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品标题', + `body` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商品描述', + `amount` bigint NOT NULL COMMENT '支付金额,单位:分', + `channel_fee_rate` double NOT NULL DEFAULT '0' COMMENT '渠道手续费,单位:百分比', + `channel_fee_amount` bigint NOT NULL DEFAULT '0' COMMENT '渠道手续金额,单位:分', + `status` tinyint NOT NULL COMMENT '支付状态', + `notify_status` tinyint NOT NULL COMMENT '通知商户支付结果的回调状态', + `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户 IP', + `expire_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '订单失效时间', + `success_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '订单支付成功时间', + `success_extension_id` bigint DEFAULT NULL COMMENT '支付成功的订单拓展单编号', + `channel_extras` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '支付渠道的额外参数', + `notify_url` varchar(1024) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '异步通知地址', + `refund_status` tinyint NOT NULL COMMENT '退款状态', + `refund_times` tinyint NOT NULL COMMENT '退款次数', + `refund_amount` bigint NOT NULL COMMENT '退款总金额,单位:分', + `channel_user_id` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '渠道用户编号', + `channel_order_no` varchar(64) DEFAULT NULL COMMENT '渠道订单号', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='支付订单\n'; + +-- ---------------------------- +-- Records of pay_order +-- ---------------------------- +BEGIN; +COMMIT; + +-- ---------------------------- +-- Table structure for pay_order_extension +-- ---------------------------- +DROP TABLE IF EXISTS `pay_order_extension`; +CREATE TABLE `pay_order_extension` ( + `id` bigint NOT NULL AUTO_INCREMENT COMMENT '支付订单编号', + `no` varchar(64) NOT NULL COMMENT '支付订单号', + `order_id` bigint NOT NULL COMMENT '支付订单编号', + `channel_id` bigint NOT NULL COMMENT '渠道编号', + `channel_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '渠道编码', + `channel_callback_data` varchar(1024) NOT NULL COMMENT '支付渠道异步通知的内容', + `user_ip` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户 IP', + `status` tinyint NOT NULL COMMENT '支付状态', + `creator` varchar(64) DEFAULT '' COMMENT '创建者', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater` varchar(64) DEFAULT '' COMMENT '更新者', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除', + PRIMARY KEY (`id`) USING BTREE +) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='支付订单\n'; + +-- ---------------------------- +-- Records of pay_order_extension +-- ---------------------------- +BEGIN; +INSERT INTO `pay_order_extension` VALUES (9, '', 1, 0, '', '2021-10-23 09:27:37', '', 0, NULL, '2021-10-23 17:12:10', NULL, '2021-10-23 17:12:10', b'0'); +COMMIT; + +SET FOREIGN_KEY_CHECKS = 1; diff --git a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/SysSmsChannelService.java b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/SysSmsChannelService.java index 5724b1274..0a7220a79 100644 --- a/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/SysSmsChannelService.java +++ b/yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/sms/SysSmsChannelService.java @@ -11,7 +11,7 @@ import java.util.Collection; import java.util.List; /** - * 短信渠道Service接口 + * 短信渠道 Service 接口 * * @author zzf * @date 2021/1/25 9:24 diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/convert/order/PayOrderCoreConvert.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/convert/order/PayOrderCoreConvert.java index 8d1623f1b..3e5215cd8 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/convert/order/PayOrderCoreConvert.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/convert/order/PayOrderCoreConvert.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderExtensionDO; 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.framework.pay.core.client.dto.PayOrderUnifiedReqDTO; import org.mapstruct.Mapper; import org.mapstruct.factory.Mappers; @@ -16,4 +17,6 @@ public interface PayOrderCoreConvert { PayOrderExtensionDO convert(PayOrderSubmitReqDTO bean); + PayOrderUnifiedReqDTO convert2(PayOrderSubmitReqDTO bean); + } diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayAppDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayAppDO.java index 859e490a5..acc849cbc 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayAppDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayAppDO.java @@ -3,7 +3,8 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableId; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** * 支付应用 DO @@ -14,7 +15,13 @@ import lombok.Data; * * @author 芋道源码 */ +@TableName("pay_app") @Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor public class PayAppDO extends BaseDO { /** @@ -36,11 +43,6 @@ public class PayAppDO extends BaseDO { * 备注 */ private String remark; - /** - * 应用私钥 - * TODO 芋艿:用途 - */ - private String secret; /** * 支付结果的回调地址 */ diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDO.java index e089abc4c..2101e6634 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDO.java @@ -1,9 +1,13 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant; -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; -import lombok.Data; +import cn.iocoder.yudao.framework.pay.core.client.PayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; /** * 支付渠道 DO @@ -14,6 +18,12 @@ import lombok.Data; * @author 芋道源码 */ @Data +@TableName(value = "pay_channel", autoResultMap = true) +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor public class PayChannelDO extends BaseDO { /** @@ -48,8 +58,11 @@ public class PayChannelDO extends BaseDO { * * 关联 {@link PayAppDO#getId()} */ - private String appId; - - // TODO 芋艿:不同渠道的配置。暂时考虑硬编码 + private Long appId; + /** + * 支付渠道配置 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private PayClientConfig config; } diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayMerchantDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayMerchantDO.java index 81a3710d5..d2b20111a 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayMerchantDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayMerchantDO.java @@ -3,15 +3,22 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableId; -import lombok.Data; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; /** - * 商户信息 DO + * 支付商户信息 DO * 目前暂时没有特别的用途,主要为未来多商户提供基础。 * * @author 芋道源码 */ @Data +@TableName("pay_merchant") +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor public class PayMerchantDO extends BaseDO { /** diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java index 1bcb8eaf7..1c9fe64f5 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderDO.java @@ -3,15 +3,16 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO; -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; import java.util.Date; +import java.util.Map; /** * 支付订单 DO @@ -22,6 +23,9 @@ import java.util.Date; @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor public class PayOrderDO extends BaseDO { /** @@ -68,10 +72,10 @@ public class PayOrderDO extends BaseDO { * 商品描述信息 */ private String body; - /** - * 商户拓展参数 - */ - private String merchantExtra; +// /** +// * 商户拓展参数 +// */ +// private Map merchantExtras; // ========== 订单相关字段 ========== @@ -80,13 +84,13 @@ public class PayOrderDO extends BaseDO { */ private Long amount; /** - * 渠道手续费 + * 渠道手续费,单位:百分比 * * 冗余 {@link PayChannelDO#getFeeRate()} */ private Double channelFeeRate; /** - * 渠道手续金额 + * 渠道手续金额,单位:分 */ private Long channelFeeAmount; /** @@ -101,47 +105,34 @@ public class PayOrderDO extends BaseDO { */ private Integer notifyStatus; /** - * 客户端 IP + * 用户 IP */ - private String clientIp; - /** - * 订单支付成功时间 - */ - private Date successTime; + private String userIp; /** * 订单失效时间 */ private Date expireTime; /** - * 支付渠道的额外参数 - * - * 参见 https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html + * 订单支付成功时间 */ - private String channelExtra; - /** - * 异步通知地址 - */ - private String notifyUrl; - /** - * 页面跳转地址 - */ - private String returnUrl; + private Date successTime; /** * 支付成功的订单拓展单编号 * * 关联 {@link PayOrderDO#getId()} */ private Long successExtensionId; - - // TODO 芋艿:可能要优化 /** - * 渠道支付错误码 + * 支付渠道的额外参数 + * + * 参见 https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html */ - private String errorCode; + @TableField(typeHandler = JacksonTypeHandler.class) + private Map channelExtras; /** - * 渠道支付错误消息 + * 异步通知地址 */ - private String errorMessage; + private String notifyUrl; // ========== 退款相关字段 ========== /** diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java index 2165a1f90..f2734f8b1 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayOrderExtensionDO.java @@ -4,9 +4,7 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChann import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import com.baomidou.mybatisplus.annotation.TableName; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.experimental.Accessors; +import lombok.*; /** * 支付订单拓展 DO @@ -17,7 +15,10 @@ import lombok.experimental.Accessors; @TableName("pay_order_extension") @Data @EqualsAndHashCode(callSuper = true) -@Accessors(chain = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor public class PayOrderExtensionDO extends BaseDO { /** @@ -25,7 +26,7 @@ public class PayOrderExtensionDO extends BaseDO { */ private Long id; /** - * 订单号,根据规则生成 + * 支付订单号,根据规则生成 * 调用支付渠道时,使用该字段作为对接的订单号。 * 1. 调用微信支付 https://api.mch.weixin.qq.com/pay/unifiedorder 时,使用该字段作为 out_trade_no * 2. 调用支付宝 https://opendocs.alipay.com/apis 时,使用该字段作为 out_trade_no @@ -50,9 +51,9 @@ public class PayOrderExtensionDO extends BaseDO { */ private Integer channelCode; /** - * 客户端 IP + * 用户 IP */ - private String clientIp; + private String userIp; /** * 支付状态 * diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java index cf526ec16..9b88ea119 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java @@ -67,10 +67,10 @@ public class PayRefundDO extends BaseDO { * 例如说,内部系统 A 的退款订单号。需要保证每个 PayMerchantDO 唯一 TODO 芋艿:需要在测试下 */ private String merchantRefundNo; - /** - * 商户拓展参数 - */ - private String merchantExtra; +// /** +// * 商户拓展参数 +// */ +// private String merchantExtra; // ========== 退款相关字段 ========== /** @@ -85,9 +85,9 @@ public class PayRefundDO extends BaseDO { */ private Integer notifyStatus; /** - * 客户端 IP + * 用户 IP */ - private String clientIp; + private String userIp; /** * 退款金额,单位:分 */ @@ -115,16 +115,6 @@ public class PayRefundDO extends BaseDO { */ private String notifyUrl; - // TODO 芋艿:可能要优化 - /** - * 渠道支付错误码 - */ - private String errorCode; - /** - * 渠道支付错误消息 - */ - private String errorMessage; - // ========== 渠道相关字段 ========== /** * 渠道订单号 diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapper.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapper.java index 153df1ec5..d8780a92f 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapper.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapper.java @@ -3,6 +3,9 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.merchant; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; + +import java.util.Date; @Mapper public interface PayChannelCoreMapper extends BaseMapperX { @@ -11,4 +14,7 @@ public interface PayChannelCoreMapper extends BaseMapperX { return selectOne("app_id", appId, "code", code); } + @Select("SELECT id FROM pay_channel WHERE update_time > #{maxUpdateTime} LIMIT 1") + Long selectExistsByUpdateTimeAfter(Date maxUpdateTime); + } diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeConstants.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java similarity index 84% rename from yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeConstants.java rename to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java index 8901671fe..a7ce78810 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeConstants.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/PayErrorCodeCoreConstants.java @@ -3,11 +3,11 @@ package cn.iocoder.yudao.coreservice.modules.pay.enums; import cn.iocoder.yudao.framework.common.exception.ErrorCode; /** - * Pay 错误码枚举类 + * Pay 错误码 Core 枚举类 * * pay 系统,使用 1-007-000-000 段 */ -public interface PayErrorCodeConstants { +public interface PayErrorCodeCoreConstants { // ========== APP 模块 1-007-000-000 ========== ErrorCode PAY_APP_NOT_FOUND = new ErrorCode(1007000000, "App 不存在"); @@ -15,7 +15,8 @@ public interface PayErrorCodeConstants { // ========== CHANNEL 模块 1-007-001-000 ========== ErrorCode PAY_CHANNEL_NOT_FOUND = new ErrorCode(1007001000, "支付渠道的配置不存在"); - ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001000, "支付渠道已经禁用"); + ErrorCode PAY_CHANNEL_IS_DISABLE = new ErrorCode(1007001001, "支付渠道已经禁用"); + ErrorCode PAY_CHANNEL_CLIENT_NOT_FOUND = new ErrorCode(1007001002, "支付渠道的客户端不存在"); // ========== ORDER 模块 1-007-002-000 ========== ErrorCode PAY_ORDER_NOT_FOUND = new ErrorCode(100401000, "支付订单不存在"); diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/PayChannelCoreService.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/PayChannelCoreService.java index 8fb9f8858..4d4aaa23d 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/PayChannelCoreService.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/PayChannelCoreService.java @@ -10,6 +10,11 @@ import cn.iocoder.yudao.framework.common.exception.ServiceException; */ public interface PayChannelCoreService { + /** + * 初始化支付客户端 + */ + void initPayClients(); + /** * 支付渠道的合法性 * diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayAppCoreServiceImpl.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayAppCoreServiceImpl.java index 784a213a3..916b50137 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayAppCoreServiceImpl.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayAppCoreServiceImpl.java @@ -10,7 +10,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.validation.Valid; -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants.*; +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java index b5cd3bc1d..64e5240c2 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/merchant/impl/PayChannelCoreServiceImpl.java @@ -1,17 +1,25 @@ package cn.iocoder.yudao.coreservice.modules.pay.service.merchant.impl; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.merchant.PayChannelCoreMapper; -import cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants; +import cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants; import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.validation.Valid; -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants.*; +import java.util.Comparator; +import java.util.Date; +import java.util.List; + +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** @@ -24,9 +32,67 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @Slf4j public class PayChannelCoreServiceImpl implements PayChannelCoreService { + /** + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 + */ + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; + + /** + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 + */ + private volatile Date maxUpdateTime; + @Resource private PayChannelCoreMapper payChannelCoreMapper; + @Resource + private PayClientFactory payClientFactory; + + @Override + public void initPayClients() { + // 获取支付渠道,如果有更新 + List payChannels = this.loadPayChannelIfUpdate(maxUpdateTime); + if (CollUtil.isEmpty(payChannels)) { + return; + } + + // 创建或更新支付 Client + payChannels.forEach(payChannel -> payClientFactory.createOrUpdatePayClient(payChannel.getId(), + payChannel.getCode(), payChannel.getConfig())); + + // 写入缓存 + assert payChannels.size() > 0; // 断言,避免告警 + maxUpdateTime = payChannels.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); + log.info("[initPayClients][初始化 PayChannel 数量为 {}]", payChannels.size()); + } + + @Scheduled(fixedDelay = SCHEDULER_PERIOD, initialDelay = SCHEDULER_PERIOD) + public void schedulePeriodicRefresh() { + initPayClients(); + } + + /** + * 如果支付渠道发生变化,从数据库中获取最新的全量支付渠道。 + * 如果未发生变化,则返回空 + * + * @param maxUpdateTime 当前支付渠道的最大更新时间 + * @return 支付渠道列表 + */ + private List loadPayChannelIfUpdate(Date maxUpdateTime) { + // 第一步,判断是否要更新。 + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 + log.info("[loadPayChannelIfUpdate][首次加载全量支付渠道]"); + } else { // 判断数据库中是否有更新的支付渠道 + if (payChannelCoreMapper.selectExistsByUpdateTimeAfter(maxUpdateTime) == null) { + return null; + } + log.info("[loadPayChannelIfUpdate][增量加载全量支付渠道]"); + } + // 第二步,如果有更新,则从数据库加载所有支付渠道 + return payChannelCoreMapper.selectList(); + } + @Override public PayChannelDO validPayChannel(Long appId, String code) { PayChannelDO channel = payChannelCoreMapper.selectByAppIdAndCode(appId, code); @@ -34,7 +100,7 @@ public class PayChannelCoreServiceImpl implements PayChannelCoreService { throw exception(PAY_CHANNEL_NOT_FOUND); } if (CommonStatusEnum.DISABLE.getStatus().equals(channel.getStatus())) { - throw exception(PayErrorCodeConstants.PAY_CHANNEL_IS_DISABLE); + throw exception(PayErrorCodeCoreConstants.PAY_CHANNEL_IS_DISABLE); } return channel; } diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderCreateReqDTO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderCreateReqDTO.java index 17a27fcfa..15d8bb48d 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderCreateReqDTO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderCreateReqDTO.java @@ -21,10 +21,10 @@ public class PayOrderCreateReqDTO implements Serializable { @NotEmpty(message = "应用编号不能为空") private Long appId; /** - * 客户端 IP + * 用户 IP */ - @NotEmpty(message = "客户端 IP 不能为空") - private String clientIp; + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; // ========== 商户相关字段 ========== @@ -40,7 +40,7 @@ public class PayOrderCreateReqDTO implements Serializable { @Length(max = 32, message = "商品标题不能超过 32") private String subject; /** - * 商品描述信息 + * 商品描述 */ @NotEmpty(message = "商品描述信息不能为空") @Length(max = 128, message = "商品描述信息长度不能超过128") diff --git a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java index c35ae23d9..542d5a52e 100644 --- a/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java +++ b/yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayOrderSubmitReqDTO.java @@ -33,9 +33,9 @@ public class PayOrderSubmitReqDTO implements Serializable { private String channelCode; /** - * 客户端 IP + * 用户 IP */ - @NotEmpty(message = "客户端 IP 不能为空") - private String clientIp; + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; } 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 9d6b13123..f843ef780 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,8 @@ import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmit import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.PayClient; +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -25,8 +27,7 @@ import javax.annotation.Resource; import javax.validation.Valid; import java.util.Date; -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants.PAY_ORDER_NOT_FOUND; -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING; +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; /** @@ -44,6 +45,9 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { @Resource private PayChannelCoreService payChannelCoreService; + @Resource + private PayClientFactory payClientFactory; + @Resource private PayOrderCoreMapper payOrderCoreMapper; @Resource @@ -79,6 +83,12 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { PayAppDO app = payAppCoreService.validPayApp(reqDTO.getId()); // 校验支付渠道是否有效 PayChannelDO channel = payChannelCoreService.validPayChannel(reqDTO.getId(), reqDTO.getChannelCode()); + // 校验支付客户端是否正确初始化 + PayClient client = payClientFactory.getPayClient(channel.getId()); + if (client == null) { + log.error("[submitPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); + throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); + } // 获得 PayOrderDO ,并校验其是否存在 PayOrderDO order = payOrderCoreMapper.selectById(reqDTO.getId()); @@ -96,13 +106,14 @@ public class PayOrderCoreServiceImpl implements PayOrderCoreService { payOrderExtensionCoreMapper.insert(orderExtension); // 调用三方接口 - AbstractThirdPayClient thirdPayClient = ThirdPayClientFactory.getThirdPayClient(submitReqDTO.getPayChannel()); - CommonResult invokeResult = thirdPayClient.submitTransaction(payTransaction, orderExtension, null); // TODO 暂时传入 extra = null + // TODO 暂时传入 extra = null + CommonResult invokeResult = client.unifiedOrder(PayOrderCoreConvert.INSTANCE.convert2(reqDTO)); invokeResult.checkError(); // TODO 轮询三方接口,是否已经支付的任务 // 返回成功 - return new PayOrderSubmitRespDTO().setExtensionId(orderExtension.getId()).setInvokeResponse(invokeResult.getData()); + return new PayOrderSubmitRespDTO().setExtensionId(orderExtension.getId()) + .setInvokeResponse(JsonUtils.toJsonString(invokeResult)); } private String generateOrderExtensionNo() { diff --git a/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbAndRedisIntegrationTest.java b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbAndRedisIntegrationTest.java new file mode 100644 index 000000000..dc1580894 --- /dev/null +++ b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbAndRedisIntegrationTest.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.coreservice; + +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbAndRedisIntegrationTest.Application.class) +@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 +public class BaseDbAndRedisIntegrationTest { + + @Import({ + // DB 配置类 + DynamicDataSourceAutoConfiguration.class, // Dynamic Datasource 配置类 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + // MyBatis 配置类 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + + // Redis 配置类 + RedisAutoConfiguration.class, // Spring Redis 自动配置类 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 + RedissonAutoConfiguration.class, // Redisson 自动高配置类 + }) + public static class Application { + } + +} diff --git a/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbIntegrationTest.java b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbIntegrationTest.java new file mode 100644 index 000000000..c0ebe9873 --- /dev/null +++ b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseDbIntegrationTest.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.coreservice; + +import cn.iocoder.yudao.framework.datasource.config.YudaoDataSourceAutoConfiguration; +import cn.iocoder.yudao.framework.mybatis.config.YudaoMybatisAutoConfiguration; +import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration; +import com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseDbIntegrationTest.Application.class) +@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 +public class BaseDbIntegrationTest { + + @Import({ + // DB 配置类 + DynamicDataSourceAutoConfiguration.class, // Dynamic Datasource 配置类 + YudaoDataSourceAutoConfiguration.class, // 自己的 DB 配置类 + DataSourceAutoConfiguration.class, // Spring DB 自动配置类 + DataSourceTransactionManagerAutoConfiguration.class, // Spring 事务自动配置类 + // MyBatis 配置类 + YudaoMybatisAutoConfiguration.class, // 自己的 MyBatis 配置类 + MybatisPlusAutoConfiguration.class, // MyBatis 的自动配置类 + }) + public static class Application { + } + +} diff --git a/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseRedisIntegrationTest.java b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseRedisIntegrationTest.java new file mode 100644 index 000000000..16b5e98f1 --- /dev/null +++ b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/BaseRedisIntegrationTest.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.coreservice; + +import cn.iocoder.yudao.framework.redis.config.YudaoRedisAutoConfiguration; +import org.redisson.spring.starter.RedissonAutoConfiguration; +import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.ActiveProfiles; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = BaseRedisIntegrationTest.Application.class) +@ActiveProfiles("integration-test") // 设置使用 application-integration-test 配置文件 +public class BaseRedisIntegrationTest { + + @Import({ + // Redis 配置类 + RedisAutoConfiguration.class, // Spring Redis 自动配置类 + YudaoRedisAutoConfiguration.class, // 自己的 Redis 配置类 + RedissonAutoConfiguration.class, // Redisson 自动高配置类 + }) + public static class Application { + } + +} diff --git a/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDOTest.java b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDOTest.java new file mode 100644 index 000000000..c0fb7d5bd --- /dev/null +++ b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/merchant/PayChannelDOTest.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant; + +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; +import org.junit.jupiter.api.Test; + +public class PayChannelDOTest { + + @Test + public void testSerialization() { + PayChannelDO payChannelDO = new PayChannelDO(); + // 创建配置 + WXPayClientConfig config = new WXPayClientConfig(); + config.setAppId("wx041349c6f39b268b"); + config.setMchId("1545083881"); + config.setApiVersion(WXPayClientConfig.API_VERSION_V2); + config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); + payChannelDO.setConfig(config); + + // 序列化 + String text = JsonUtils.toJsonString(payChannelDO); + System.out.println(text); + + // 反序列化 + payChannelDO = JsonUtils.parseObject(text, PayChannelDO.class); + System.out.println(payChannelDO.getConfig().getClass()); + } + +} diff --git a/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapperTest.java b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapperTest.java new file mode 100644 index 000000000..b214f7b65 --- /dev/null +++ b/yudao-core-service/src/test-integration/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/merchant/PayChannelCoreMapperTest.java @@ -0,0 +1,56 @@ +package cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.merchant; + +import cn.hutool.core.io.IoUtil; +import cn.iocoder.yudao.coreservice.BaseDbAndRedisIntegrationTest; +import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.pay.core.client.impl.wx.WXPayClientConfig; +import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; +import org.junit.jupiter.api.Test; + +import javax.annotation.Resource; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.util.List; + +@Resource +public class PayChannelCoreMapperTest extends BaseDbAndRedisIntegrationTest { + + @Resource + private PayChannelCoreMapper payChannelCoreMapper; + + /** + * 插入初始配置 + */ + @Test + public void testInsert() throws FileNotFoundException { + PayChannelDO payChannelDO = new PayChannelDO(); + payChannelDO.setCode(PayChannelEnum.WX_PUB.getCode()); + payChannelDO.setStatus(CommonStatusEnum.ENABLE.getStatus()); + payChannelDO.setFeeRate(1D); + payChannelDO.setMerchantId(1L); + payChannelDO.setAppId(6L); + // 配置 + WXPayClientConfig config = new WXPayClientConfig(); + config.setAppId("wx041349c6f39b268b"); + config.setMchId("1545083881"); + config.setApiVersion(WXPayClientConfig.API_VERSION_V2); + config.setMchKey("0alL64UDQdlCwiKZ73ib7ypaIjMns06p"); + config.setPrivateKeyContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_key.pem"))); + config.setPrivateCertContent(IoUtil.readUtf8(new FileInputStream("/Users/yunai/Downloads/wx_pay/apiclient_cert.pem"))); + config.setApiV3Key("joerVi8y5DJ3o4ttA0o1uH47Xz1u2Ase"); + payChannelDO.setConfig(config); + // 执行插入 + payChannelCoreMapper.insert(payChannelDO); + } + + /** + * 查询所有支付配置,看看是否都是 ok 的 + */ + @Test + public void testSelectList() { + List payChannels = payChannelCoreMapper.selectList(); + System.out.println(payChannels.size()); + } + +} diff --git a/yudao-core-service/src/test-integration/resources/application-integration-test.yaml b/yudao-core-service/src/test-integration/resources/application-integration-test.yaml new file mode 100644 index 000000000..06796faab --- /dev/null +++ b/yudao-core-service/src/test-integration/resources/application-integration-test.yaml @@ -0,0 +1,92 @@ +spring: + main: + lazy-initialization: true # 开启懒加载,加快速度 + banner-mode: off # 单元测试,禁用 Banner + +--- #################### 数据库相关配置 #################### + +spring: + # 数据源配置项 + autoconfigure: + exclude: + - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure # 排除 Druid 的自动配置,使用 dynamic-datasource-spring-boot-starter 配置多数据源 + datasource: + druid: # Druid 【监控】相关的全局配置 + web-stat-filter: + enabled: true + dynamic: # 多数据源配置 + druid: # Druid 【连接池】相关的全局配置 + initial-size: 5 # 初始连接数 + min-idle: 10 # 最小连接池数量 + max-active: 20 # 最大连接池数量 + max-wait: 600000 # 配置获取连接等待超时的时间,单位:毫秒 + time-between-eviction-runs-millis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位:毫秒 + min-evictable-idle-time-millis: 300000 # 配置一个连接在池中最小生存的时间,单位:毫秒 + max-evictable-idle-time-millis: 900000 # 配置一个连接在池中最大生存的时间,单位:毫秒 + validation-query: SELECT 1 FROM DUAL # 配置检测连接是否有效 + test-while-idle: true + test-on-borrow: false + test-on-return: false + primary: master + datasource: + master: + name: ruoyi-vue-pro + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.master.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 123456 + slave: # 模拟从库,可根据自己需要修改 + name: ruoyi-vue-pro + url: jdbc:mysql://127.0.0.1:3306/${spring.datasource.dynamic.datasource.slave.name}?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=CTT + driver-class-name: com.mysql.jdbc.Driver + username: root + password: 123456 + + # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 + redis: + host: 127.0.0.1 # 地址 + port: 6379 # 端口 + database: 0 # 数据库索引 + +mybatis: + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试 +mybatis-plus: + configuration: + map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。 + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志 + global-config: + db-config: + id-type: AUTO # 自增 ID + logic-delete-value: 1 # 逻辑已删除值(默认为 1) + logic-not-delete-value: 0 # 逻辑未删除值(默认为 0) + mapper-locations: classpath*:mapper/*.xml + type-aliases-package: ${yudao.info.base-package}.modules.*.dal.dataobject, ${yudao.core-service.base-package}.modules.*.dal.dataobject + +--- #################### 定时任务相关配置 #################### + +--- #################### 配置中心相关配置 #################### + +--- #################### 服务保障相关配置 #################### + +# Lock4j 配置项(单元测试,禁用 Lock4j) + +# Resilience4j 配置项 +resilience4j: + ratelimiter: + instances: + backendA: + limit-for-period: 1 # 每个周期内,允许的请求数。默认为 50 + limit-refresh-period: 60s # 每个周期的时长,单位:微秒。默认为 500 + timeout-duration: 1s # 被限流时,阻塞等待的时长,单位:微秒。默认为 5s + register-health-indicator: true # 是否注册到健康监测 + +--- #################### 监控相关配置 #################### + +--- #################### 芋道相关配置 #################### + +yudao: + info: + version: 1.0.0 + base-package: cn.iocoder.yudao.adminserver + core-service: + base-package: cn.iocoder.yudao.coreservice diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml b/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml index 16b8b9368..f7be5c619 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/pom.xml @@ -22,6 +22,12 @@ yudao-common + + + org.springframework.boot + spring-boot-starter + + jakarta.validation @@ -47,16 +53,6 @@ - - - - - - - - - - com.alipay.sdk alipay-sdk-java diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java new file mode 100644 index 000000000..fc2b20253 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/config/YudaoPayAutoConfiguration.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.framework.pay.config; + +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; +import cn.iocoder.yudao.framework.pay.core.client.impl.PayClientFactoryImpl; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * 支付配置类 + * + * @author 芋道源码 + */ +@Configuration +public class YudaoPayAutoConfiguration { + + @Bean + public PayClientFactory payClientFactory() { + return new PayClientFactoryImpl(); + } + +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java index 4b7ff57b1..8d66aedbf 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientConfig.java @@ -1,10 +1,16 @@ package cn.iocoder.yudao.framework.pay.core.client; +import com.fasterxml.jackson.annotation.JsonTypeInfo; + /** * 支付客户端的配置,本质是支付渠道的配置 * 每个不同的渠道,需要不同的配置,通过子类来定义 * * @author 芋道源码 */ +@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) +// @JsonTypeInfo 注解的作用,Jackson 多态 +// 1. 序列化到时数据库时,增加 @class 属性。 +// 2. 反序列化到内存对象时,通过 @class 属性,可以创建出正确的类型 public interface PayClientConfig { } 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 5d8c087ee..cd1159adf 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 @@ -16,10 +16,10 @@ import java.util.Date; public class PayOrderUnifiedReqDTO { /** - * 客户端 IP + * 用户 IP */ - @NotEmpty(message = "客户端 IP 不能为空") - private String clientIp; + @NotEmpty(message = "用户 IP 不能为空") + private String userIp; // ========== 商户相关字段 ========== 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 c1d6f691a..96f5a286c 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 @@ -49,7 +49,7 @@ public class AlipayQrPayClient extends AbstractPayClient model.setSubject(reqDTO.getSubject()); model.setBody(reqDTO.getBody()); model.setTotalAmount(calculateAmount(reqDTO.getAmount()).toString()); // 单位:元 - // TODO 芋艿:clientIp + expireTime + // TODO 芋艿:userIp + expireTime // 构建 AlipayTradePrecreateRequest AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest(); request.setBizModel(model); 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 15fd5fb75..94265b951 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 @@ -46,7 +46,7 @@ public class AlipayWapPayClient extends AbstractPayClient model.setTotalAmount(calculateAmount(reqDTO.getAmount()).toString()); model.setProductCode("QUICK_WAP_PAY"); // TODO 芋艿:这里咋整 model.setSellerId("2088102147948060"); // TODO 芋艿:这里咋整 - // TODO 芋艿:clientIp + expireTime + // TODO 芋艿:userIp + expireTime // 构建 AlipayTradeWapPayRequest AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest(); request.setBizModel(model);