refactor(alipay): DTO 强类型化 + client 分包 + 子应用 service 重构

- DTO 强类型: config Map→AlipaySdkCredential, method String→AlipayPayMethod,
  payBodyType String→AlipayPayBodyType, expireTime/finishTime String→OffsetDateTime
- 字段贴近支付宝: outTradeNo/tradeNo/body, 删 channel/otherMethod/transOrderNo
- notifyUrl 从 config Map 拆出为 Req 独立字段
- 删除通用 ChannelPayReq/ChannelPayResp(仅 alipay 使用)
- 主应用 client 分包: req/resp/enums/credential 四子包
- 沙箱字段: AlipayDirectConfigAssembler 从 PayProductConfig.activeEnv 读取
- 子应用: 删 demo 模式, pay() 分发 payWap/payApp/payPage/payQr 子方法
- 子应用 dto→req/resp 分包
- 新增 PayBodyTypeEnum QR_CODE/ORDER_STR 枚举值
This commit is contained in:
DaxPay Dev
2026-07-01 16:16:22 +08:00
parent 78249e737c
commit 58fef669c7
19 changed files with 257 additions and 128 deletions

View File

@@ -12,7 +12,7 @@
Target Server Version : 160009 (160009)
File Encoding : 65001
Date: 27/06/2026 18:30:43
Date: 01/07/2026 15:07:57
*/
@@ -90,27 +90,27 @@ COMMENT ON TABLE "public"."iam_perm_menu" IS '菜单权限配置';
-- ----------------------------
INSERT INTO "public"."iam_perm_menu" VALUES (202, 2, NULL, 'admin', 'FileUploadDemo', '文件上传演示', 'File Upload Demo', 'menu.demos.fileUpload', 'lucide:upload', 'f', 'f', '/demos/file-upload/FileUploadDemo', '/demos/file-upload', NULL, 2, 'f', 't', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-09 16:00:00+00', '2026-04-09 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (307, 3, 'system:monitor', 'admin', 'SystemMonitor', '系统监控', 'System Monitor', 'menu.system.monitor', 'lucide:monitor', 'f', 'f', NULL, '/system/monitor', NULL, 50, 'f', 't', 'f', 1, 1, 1, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-10 16:00:00+00', '2026-04-12 12:53:45.790453+00');
INSERT INTO "public"."iam_perm_menu" VALUES (101, 1, 'dashboard:analytics', 'admin', 'Analytics', '分析页', 'Analytics', 'menu.dashboard.analytics', 'lucide:area-chart', 'f', 'f', '/dashboard/analytics/index', '/analytics', NULL, 2, 'f', 'f', 't', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-20 03:11:13.134079+00');
INSERT INTO "public"."iam_perm_menu" VALUES (305, 3, 'iam:perm', 'admin', 'SystemPerm', '权限管理', 'Permission Management', 'menu.system.perm', 'lucide:shield', 'f', 'f', NULL, '/system/perm', NULL, 2, 'f', 't', 'f', 1, 1, 1, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-08 16:00:00+00', '2026-04-09 15:10:44.651238+00');
INSERT INTO "public"."iam_perm_menu" VALUES (302, 3, NULL, 'admin', 'SystemLog', '日志管理', 'Log Management', 'menu.system.log', 'lucide:file-text', 'f', 'f', NULL, '/system/log', NULL, 99, 'f', 't', 'f', 0, 1, 1, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-04-05 08:56:11.97756+00');
INSERT INTO "public"."iam_perm_menu" VALUES (1, NULL, NULL, 'admin', 'Dashboard', '仪表板', 'Dashboard', 'menu.dashboard', 'lucide:layout-dashboard', 'f', 'f', NULL, '/dashboard', '/workspace', -1, 'f', 'f', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-20 03:11:13.134079+00');
INSERT INTO "public"."iam_perm_menu" VALUES (304, 3, 'system:config', 'admin', 'SystemConfig', '系统配置', 'System Config', 'menu.system.config', 'lucide:settings-2', 'f', 'f', NULL, '/system/config', NULL, 10, 'f', 't', 'f', 0, 1, 1, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-04 16:00:00+00', '2026-04-09 15:11:00.840153+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30701, 307, 'iam:online:user', 'admin', 'OnlineUser', '在线用户', 'Online User', 'menu.system.monitor.online', 'lucide:users', 'f', 'f', '/system/monitor/online/OnlineUserList', '/system/monitor/online', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-11 16:00:00+00', '2026-04-11 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (401, 4, 'payment:platform', 'admin', 'PaymentPlatform', '支付主数据', 'Payment Master Data', 'menu.payment.platform', 'lucide:building', 'f', 'f', NULL, '/payment/platform', NULL, 1, 'f', 't', 'f', 0, 1, 3, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 16:00:00+00', '2026-05-28 06:25:42.880461+00');
INSERT INTO "public"."iam_perm_menu" VALUES (203, 2, 'demos:region', 'admin', 'RegionCascaderDemo', '行政区划选择器', 'Region Cascader', 'menu.demos.region', 'lucide:map-pin', 'f', 'f', '/demos/region/RegionCascaderDemo', '/demos/region', NULL, 3, 'f', 't', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-24 16:00:00+00', '2026-04-24 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (6, NULL, 'trade', 'admin', 'TransactionManagement', '交易管理', 'Transaction Management', 'menu.trade', 'lucide:arrow-left-right', 'f', 'f', NULL, '/trade', '/trade/index', 3.5, 'f', 't', 'f', 1, 1, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-24 16:00:00+00', '2026-05-24 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (3, NULL, NULL, 'admin', 'System', '系统管理', 'System', 'menu.system', 'lucide:sliders-horizontal', 'f', 'f', NULL, '/system', NULL, 0, 'f', 't', 'f', 0, 1, 2, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-06-25 02:00:30.22348+00');
INSERT INTO "public"."iam_perm_menu" VALUES (102, 1, 'dashboard:workspace', 'admin', 'Workspace', '工作台', 'Workspace', 'menu.dashboard.workspace', 'lucide:panels-top-left', 'f', 'f', '/dashboard/workspace/index', '/workspace', NULL, 1, 'f', 'f', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-06-25 02:00:30.233427+00');
INSERT INTO "public"."iam_perm_menu" VALUES (301, 3, NULL, 'admin', 'SystemBasic', '基础数据', 'Basic Data', 'menu.system.basic', 'lucide:boxes', 'f', 'f', NULL, '/system/basic', NULL, 1, 'f', 't', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-06-25 02:00:30.236321+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30101, 301, 'system:dict', 'admin', 'SystemDict', '字典管理', 'Dictionary', 'menu.system.basic.dict', 'lucide:book-open', 'f', 'f', '/system/basic/dict/DictList', '/system/basic/dict', NULL, 1, 'f', 't', 'f', 0, 1, 2, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-06-25 02:00:30.243488+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30401, 304, 'system:security_config', 'admin', 'SecurityConfig', '安全配置', 'Security Config', 'menu.system.config.security', 'lucide:shield-check', 'f', 'f', '/system/config/security/SecurityConfig', '/system/config/security', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 02:00:00+00', '2026-06-27 13:01:24.303469+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30402, 304, 'system:platform_config', 'admin', 'PlatformConfig', '平台配置', 'Platform Config', 'menu.system.config.platform', 'lucide:settings', 'f', 'f', '/system/config/platform/PlatformConfig', '/system/config/platform', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-07 16:00:00+00', '2026-06-27 13:01:24.311831+00');
INSERT INTO "public"."iam_perm_menu" VALUES (2, NULL, NULL, 'admin', 'Demos', '演示', 'Demos', 'menu.demos', 'lucide:blocks', 'f', 'f', NULL, '/demos', NULL, 1000, 'f', 't', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-06-25 02:00:30.27727+00');
INSERT INTO "public"."iam_perm_menu" VALUES (1, NULL, NULL, 'admin', 'Dashboard', '仪表板', 'Dashboard', 'menu.dashboard', 'lucide:layout-dashboard', 'f', 'f', NULL, '/dashboard', '/workspace', -1, 'f', 'f', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-06-27 13:46:52.151771+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30202, 302, 'system:log:operate', 'admin', 'SystemOperateLog', '操作日志', 'Operate Log', 'menu.system.log.operate', 'lucide:activity', 'f', 'f', '/system/log/operate/OperateLogList', '/system/log/operate', NULL, 2, 'f', 't', 'f', 0, 1, 1, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-30 15:24:57.076166+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40401, 404, 'merchant:info', 'admin', 'MerchantInfo', '商户信息', 'Merchant Info', 'menu.merchant.info', 'lucide:shopping-bag', 'f', 'f', '/payment/merchant/info/MerchantList', '/payment/merchant/info', NULL, 1, 'f', 't', 'f', 1, 1, 1, 'f', 'menu', NULL, NULL, NULL, NULL, '', '', '2026-04-13 16:00:00+00', '2026-06-25 02:00:30.290399+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30601, 307, 'system:file:platform', 'admin', 'StorageFile', '存储文件', 'Storage File', 'menu.system.monitor.file', 'lucide:files', 'f', 'f', '/system/monitor/file/PlatformFileList', '/system/monitor/file', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-09 16:00:00+00', '2026-06-25 02:43:43.71511+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4, NULL, 'payment', 'admin', 'PaymentSystem', '平台管理', 'Platform Management', 'menu.platform', 'lucide:credit-card', 'f', 'f', NULL, '/payment', NULL, 3, 'f', 't', 'f', 0, 1, 1, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 16:00:00+00', '2026-06-13 00:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30201, 302, 'system:log:login', 'admin', 'SystemLoginLog', '登录日志', 'Login Log', 'menu.system.log.login', 'lucide:log-in', 'f', 'f', '/system/log/login/LoginLogList', '/system/log/login', NULL, 1, 'f', 't', 'f', 0, 1, 1, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-03-20 03:11:13.134079+00', '2026-03-30 15:25:09.855555+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30401, 304, 'system:securityConfig', 'admin', 'SecurityConfig', '安全配置', 'Security Config', 'menu.system.config.security', 'lucide:shield-check', 'f', 'f', '/system/config/security/SecurityConfig', '/system/config/security', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 02:00:00+00', '2026-04-05 02:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30402, 304, 'system:platformConfig', 'admin', 'PlatformConfig', '平台配置', 'Platform Config', 'menu.system.config.platform', 'lucide:settings', 'f', 'f', '/system/config/platform/PlatformConfig', '/system/config/platform', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-07 16:00:00+00', '2026-04-07 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (102, 1, 'dashboard:workspace', 'admin', 'Workspace', '工作台', 'Workspace', 'menu.dashboard.workspace', 'lucide:panels-top-left', 'f', 'f', '/dashboard/workspace/index', '/workspace', NULL, 1, 'f', 'f', 't', 0, 1, 1, 'f', 'menu', NULL, NULL, NULL, NULL, '', '', '2026-03-20 03:11:13.134079+00', '2026-06-28 02:50:37.055128+00');
INSERT INTO "public"."iam_perm_menu" VALUES (101, 1, 'dashboard:analytics', 'admin', 'Analytics', '分析页', 'Analytics', 'menu.dashboard.analytics', 'lucide:area-chart', 'f', 'f', '/dashboard/analytics/index', '/analytics', NULL, 2, 'f', 'f', 'f', 0, 1, 1, 'f', 'menu', NULL, NULL, NULL, NULL, '', '', '2026-03-20 03:11:13.134079+00', '2026-06-28 02:50:43.072618+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30103, 305, 'iam:role', 'admin', 'SystemRole', '角色管理', 'Role Management', 'menu.system.perm.role', 'lucide:shield-user', 'f', 'f', '/iam/perm/role/RoleList', '/iam/perm/role', NULL, 3, 'f', 't', 'f', 0, 1, 2, 'f', 'menu', NULL, NULL, NULL, NULL, '', '', '2026-03-20 03:11:13.134079+00', '2026-06-25 02:00:30.246504+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30501, 305, 'iam:user:manager', 'admin', 'UserList', '用户管理', 'User Management', 'menu.system.perm.user', 'lucide:users-round', 'f', 'f', 'views/iam/user/UserList', '/iam/user', NULL, 10, 'f', 't', 'f', 1, 1, 4, 'f', 'menu', NULL, NULL, NULL, NULL, '', '', '2026-03-31 00:23:04.37507+00', '2026-06-25 02:00:30.279649+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30102, 301, 'iam:perm:menu', 'admin', 'SystemMenu', '菜单管理', 'Menu Management', 'menu.system.perm.menu', 'lucide:panel-top', 'f', 'f', '/iam/perm/menu/MenuList', '/system/basic/menu', NULL, 0, 'f', 't', 'f', 0, 1, 3, 'f', 'menu', NULL, NULL, NULL, NULL, '', '', '2026-03-20 03:11:13.134079+00', '2026-06-27 10:29:51.371435+00');
@@ -119,8 +119,8 @@ INSERT INTO "public"."iam_perm_menu" VALUES (40104, 401, 'payment:platform:capab
INSERT INTO "public"."iam_perm_menu" VALUES (4040111, 40401, 'merchant:app:route', 'admin', 'PayRouteConfig', '通道路由', 'Channel Routing', 'menu.payment.merchant.app.payRoute', NULL, 't', 'f', '/payment/merchant/route/PayRouteConfig', '/payment/merchant/route', NULL, 2, 'f', 't', 'f', 1, 1, 1, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-24 22:23:46.483985+00', '2026-05-26 20:03:06.445803+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40102, 401, 'payment:platform:provider', 'admin', 'PayProviderList', '支付方式', 'Payment Method', 'menu.payment.platform.provider', 'lucide:list-tree', 'f', 'f', '/payment/masterdata/provider/PayMethodList', '/payment/platform/pay-method', NULL, 1, 'f', 't', 'f', 1, 1, 5, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-27 20:18:01.383008+00', '2026-05-30 08:21:19.464024+00');
INSERT INTO "public"."iam_perm_menu" VALUES (404, NULL, 'merchant', 'admin', 'PaymentMerchant', '商户管理', 'Merchant Management', 'menu.merchant', 'lucide:store', 'f', 'f', NULL, '/payment/merchant', NULL, 4, 't', 't', 'f', 0, NULL, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-05 16:00:00+00', '2026-06-13 00:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40103, 401, 'payment:platform:pay_channel', 'admin', 'PayChannelList', '支付通道', 'Payment Channel', 'menu.payment.platform.channel', 'lucide:radio-tower', 'f', 'f', '/payment/masterdata/channel/PayChannelList', '/payment/platform/pay-channel', NULL, 0, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-28 16:00:00+00', '2026-06-27 13:01:24.315365+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40101, 401, 'payment:platform:product', 'admin', 'ProductList', '支付产品', 'Payment Product', 'menu.payment.platform.product', 'lucide:package', 'f', 'f', '/payment/masterdata/product/PayProductList', '/payment/platform/product', NULL, 2, 'f', 't', 'f', 1, 1, 3, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-23 16:00:00+00', '2026-05-28 06:25:42.892396+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40103, 401, 'payment:platform:payChannel', 'admin', 'PayChannelList', '支付通道', 'Payment Channel', 'menu.payment.platform.channel', 'lucide:radio-tower', 'f', 'f', '/payment/masterdata/channel/PayChannelList', '/payment/platform/pay-channel', NULL, 0, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-28 16:00:00+00', '2026-05-28 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040101, 40401, 'merchant:workbench', 'admin', 'MerchantManage', '商户管理', 'Merchant Management', 'menu.payment.merchant.manage', '', 't', 'f', '/payment/merchant/manage/workbench/MerchantManage', '/payment/merchant/manage', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-04-13 16:00:00+00', '2026-05-02 06:57:49.052168+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040102, 40401, 'merchant:credential', 'admin', 'MerchantCredentialConfig', '对接配置', 'Credential Config', 'menu.payment.merchant.manage.credentialConfig', NULL, 't', 'f', '/payment/merchant/manage/credential/MerchantCredentialConfig', '/payment/merchant/manage/credential', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-01 16:00:00+00', '2026-05-01 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040108, 40401, 'merchant:user', 'admin', 'MerchantUser', '商户用户', 'Merchant User', 'menu.payment.merchant.user', '', 't', 'f', '/payment/merchant/user/MerchantUserList', '/payment/merchant/user', NULL, 8, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-04 16:00:00+00', '2026-05-04 16:00:00+00');
@@ -130,28 +130,30 @@ INSERT INTO "public"."iam_perm_menu" VALUES (4040109, 40401, 'channel:merchant:c
INSERT INTO "public"."iam_perm_menu" VALUES (4040114, 40401, 'channel:alipay:app', 'admin', 'AlipayMchAppManage', '支付宝通道商户应用', 'Alipay Channel Merchant App', 'menu.payment.merchant.channelMerchant.alipayApp', NULL, 't', 'f', '/payment/channel/alipay/manage/mch/app/AlipayMchAppManage', '/payment/merchant/channel-merchant/alipay-app-manage', NULL, 12, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-11 22:28:11.274785+00', '2026-06-11 22:28:11.274785+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040113, 40401, 'channel:wechat:app', 'admin', 'WechatMchAppManage', '微信通道商户应用', 'WeChat Channel Merchant App', 'menu.payment.merchant.channelMerchant.wechatApp', NULL, 't', 'f', '/payment/channel/wechat/manage/mch/app/WechatMchAppManage', '/payment/merchant/channel-merchant/wechat-app-manage', NULL, 11, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-07 23:57:13.620205+00', '2026-06-07 23:57:13.620205+00');
INSERT INTO "public"."iam_perm_menu" VALUES (405, 4, 'payment:config', 'admin', 'PaymentConfig', '支付配置', 'Payment Config', 'menu.payment.config', 'lucide:settings-2', 'f', 'f', NULL, '/payment/config', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40105, 405, 'payment:config:productConfig', 'admin', 'ProductConfig', '支付产品管理', 'Payment Product Management', 'menu.payment.config.productConfig', 'lucide:layout-grid', 'f', 'f', '/payment/config/product/ProductConfig', '/payment/config/product', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-13 00:00:00+00', '2026-06-13 09:14:10.179605+00');
INSERT INTO "public"."iam_perm_menu" VALUES (90201, 9, 'device:vendor_config', 'admin', 'VendorManage', '设备厂商管理', 'Device Vendor Management', 'menu.device.vendor', 'lucide:building-2', 'f', 'f', '/payment/device/vendor/VendorManage', '/device/vendor', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-25 01:21:34.646017+00', '2026-06-27 13:01:24.320315+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40502, 40105, 'payment:alipay:isv', 'admin', 'AlipayIsvAppManage', '支付宝服务商应用', 'Alipay ISV Application', 'menu.payment.alipay.isvApp', NULL, 't', 'f', '/payment/channel/alipay/manage/app/AlipayIsvAppManage', '/payment/config/product/app-manage', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (90202, 9, 'device:speaker', 'admin', 'DeviceSpeakerList', '云音箱管理', 'Speaker Management', 'menu.device.speaker', 'lucide:speaker', 'f', 'f', '/payment/device/speaker/DeviceSpeakerList', '/device/speaker', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-25 01:21:34.647632+00', '2026-06-25 12:51:25.245363+00');
INSERT INTO "public"."iam_perm_menu" VALUES (8, NULL, 'develop', 'admin', 'Develop', '开发调试', 'Develop', 'menu.develop', 'lucide:wrench', 'f', 'f', NULL, '/develop', NULL, 5, 'f', 't', 'f', 1, 1, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-23 16:00:00+00', '2026-06-23 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (309, 3, 'system:notify', 'admin', 'SystemNotify', '公告通知', 'Notification', 'menu.system.notify', 'lucide:bell', 'f', 'f', '/system/notify/notice/NoticeList', '/system/notify', NULL, 20, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, '2026-06-24 16:00:00+00', '2026-06-24 16:00:00+00', NULL);
INSERT INTO "public"."iam_perm_menu" VALUES (308, 3, 'system:notify', 'admin', 'SystemNotice', '通知中心', 'Notification Center', 'menu.system.notify', 'lucide:bell', 'f', 'f', NULL, '/system/notify', '/system/notify/notice', 20, 'f', 't', 'f', 1, 1, 0, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-07-01 16:00:00+00', '2026-07-01 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (309, 308, 'system:notify:notice', 'admin', 'SystemNotify', '公告通知', 'Notification', 'menu.system.notify.notice', 'lucide:megaphone', 'f', 'f', '/system/notify/notice/NoticeList', '/system/notify/notice', NULL, 20, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-07-01 16:00:00+00', '2026-07-01 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (901, 9, 'device:qrcode', 'admin', 'DeviceQrCode', '码牌管理', 'QR Code Management', 'menu.device.qrcode', 'lucide:qr-code', 't', 'f', '/_core/fallback/coming-soon', '/device/qrcode', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-25 01:21:34.634639+00', '2026-06-25 12:51:25.24304+00');
INSERT INTO "public"."iam_perm_menu" VALUES (204, 2, 'demos:artemis', 'admin', 'ArtemisDemo', '消息队列演示', 'Message Queue Demo', 'menu.demos.artemis', 'lucide:send', 'f', 'f', '/demos/artemis/ArtemisDemo', '/demos/artemis', NULL, 4, 'f', 't', 'f', 0, NULL, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-18 00:00:00+00', '2026-06-18 00:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (900001, 304, 'iam:social:config', 'admin', 'SocialConfig', '三方平台登录', 'Third-party Platform Login', 'menu.system.config.social', 'lucide:share-2', 'f', 'f', 'views/iam/social/social-config', '/system/config/social', NULL, 5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO "public"."iam_perm_menu" VALUES (30403, 304, 'system:protocol', 'admin', 'UserProtocol', '用户协议', 'User Protocol', 'menu.system.config.protocol', 'lucide:file-text', 'f', 'f', '/system/protocol/UserProtocolList', '/system/config/protocol', NULL, 10, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-24 10:32:13.183371+00', '2026-06-24 10:32:13.183371+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040106, 40401, 'channel:merchant', 'admin', 'ChannelMerchant', '通道商户', 'Channel Merchant', 'menu.payment.merchant.channelMerchant', NULL, 't', 'f', '/payment/merchant/channel-merchant/ChannelMerchantList', '/payment/merchant/channel-merchant', NULL, 6, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-05-03 16:00:00+00', '2026-05-03 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040116, 401, 'payment:platform:provider:manage', 'admin', 'PayProviderManage', '支付渠道', 'Payment Provider', 'menu.payment.platform.provider.manage', 'lucide:wallet', 'f', 'f', '/payment/masterdata/provider/PayProviderList', '/payment/platform/pay-provider', NULL, 0.5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-17 10:00:31.640482+00', '2026-06-25 01:21:34.621269+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40501, 40105, 'payment:config:productDetail', 'admin', 'ProductDetailDispatch', '支付产品详情', 'Payment Product Detail', 'menu.payment.config.productDetail', NULL, 't', 'f', '/payment/config/product/detail/ProductDetailDispatch', '/payment/product-detail', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40501, 40105, 'payment:config:product_detail', 'admin', 'ProductDetailDispatch', '支付产品详情', 'Payment Product Detail', 'menu.payment.config.productDetail', NULL, 't', 'f', '/payment/config/product/detail/ProductDetailDispatch', '/payment/product-detail', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-27 13:01:24.321883+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040103, 40401, 'merchant:mchInfo', 'admin', 'MchInfoManage', '商户信息', 'Merchant Basic Info', 'menu.payment.merchant.manage.mchInfo', NULL, 't', 'f', '/payment/merchant/manage/info/MchInfoManage', '/payment/merchant/manage/info', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO "public"."iam_perm_menu" VALUES (801, 8, 'develop:trade', 'admin', 'DevelopTrade', '支付调试', 'Payment Develop', 'menu.develop.trade', 'lucide:credit-card', 'f', 'f', '/payment/develop/trade/DevelopTrade', '/develop/trade', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-23 16:00:00+00', '2026-06-23 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (802, 8, 'develop:sign', 'admin', 'DevelopSign', '签名调试', 'Sign Develop', 'menu.develop.sign', 'lucide:file-signature', 'f', 'f', '/payment/develop/sign/DevelopSign', '/develop/sign', NULL, 2, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-23 16:00:00+00', '2026-06-23 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040117, 40401, 'merchant:store', 'admin', 'MchStoreInfoList', '门店管理', 'Store Management', 'menu.payment.merchant.store', NULL, 't', 'f', '/payment/merchant/store/MchStoreInfoList', '/payment/merchant/store', NULL, 15, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-24 16:00:00+00', '2026-06-24 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (40503, 40105, 'payment:wechat:isv', 'admin', 'WechatIsvAppManage', '微信服务商应用', 'WeChat ISV Application', 'menu.payment.wechat.isvApp', NULL, 't', 'f', '/payment/channel/wechat/manage/app/WechatIsvAppManage', '/payment/config/product/wechat-app-manage', NULL, 4, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-14 00:00:00+00', '2026-06-14 00:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040115, 40401, 'channel:douyin:app', 'admin', 'DouyinMchAppManage', '抖音通道商户应用', 'Douyin Channel Merchant App', 'menu.payment.merchant.channelMerchant.douyinApp', NULL, 't', 'f', '/payment/channel/douyin/manage/app/DouyinMchAppManage', '/payment/merchant/channel-merchant/douyin-app-manage', NULL, 13, 'f', 't', 'f', 1, 1, 0, 'f', 'subpage', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-15 16:00:00+00', '2026-06-15 16:00:00+00');
INSERT INTO "public"."iam_perm_menu" VALUES (904, 9, 'device:assistant', 'admin', 'DeviceAssistant', '辅助支付终端', 'Payment Assistant Terminal', 'menu.device.assistant', 'lucide:monitor-smartphone', 'f', 'f', '/_core/fallback/coming-soon', '/device/assistant', NULL, 5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-25 12:51:25.252086+00', '2026-06-25 12:51:25.252086+00');
INSERT INTO "public"."iam_perm_menu" VALUES (90201, 9, 'device:vendorConfig', 'admin', 'VendorManage', '设备厂商管理', 'Device Vendor Management', 'menu.device.vendor', 'lucide:building-2', 'f', 'f', '/payment/device/vendor/VendorManage', '/device/vendor', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-25 01:21:34.646017+00', '2026-06-25 12:51:25.240464+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30404, 304, 'system:oss_config', 'admin', 'OssConfig', 'OSS配置', 'OSS Config', 'menu.system.config.oss', 'lucide:hard-drive', 't', 'f', '/system/config/oss/OssConfig', '/system/config/oss', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-27 13:01:24.313531+00');
INSERT INTO "public"."iam_perm_menu" VALUES (9, NULL, 'device', 'admin', 'DeviceManagement', '设备管理', 'Device Management', 'menu.device', 'lucide:monitor-speaker', 'f', 'f', NULL, '/device', NULL, 4.2, 'f', 't', 'f', 1, 1, 1, 'f', 'catalog', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-25 01:21:34.631155+00', '2026-06-25 12:51:25.231569+00');
INSERT INTO "public"."iam_perm_menu" VALUES (90302, 9, 'device:printer', 'admin', 'DevicePrinterList', '云打印', 'Cloud Printer', 'menu.device.printer', 'lucide:printer', 'f', 'f', '/payment/device/printer/DevicePrinterList', '/device/printer', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-25 01:21:34.651889+00', '2026-06-26 02:06:38.060486+00');
INSERT INTO "public"."iam_perm_menu" VALUES (30404, 304, 'system:ossConfig', 'admin', 'OssConfig', 'OSS配置', 'OSS Config', 'menu.system.config.oss', 'lucide:hard-drive', 't', 'f', '/system/config/oss/OssConfig', '/system/config/oss', NULL, 3, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
INSERT INTO "public"."iam_perm_menu" VALUES (40105, 405, 'payment:config:product_config', 'admin', 'ProductConfig', '支付产品管理', 'Payment Product Management', 'menu.payment.config.productConfig', 'lucide:layout-grid', 'f', 'f', '/payment/config/product/ProductConfig', '/payment/config/product', NULL, 1, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-13 00:00:00+00', '2026-06-27 13:01:24.317032+00');
INSERT INTO "public"."iam_perm_menu" VALUES (4040116, 401, 'payment:platform:provider_manage', 'admin', 'PayProviderManage', '支付渠道', 'Payment Provider', 'menu.payment.platform.provider.manage', 'lucide:wallet', 'f', 'f', '/payment/masterdata/provider/PayProviderList', '/payment/platform/pay-provider', NULL, 0.5, 'f', 't', 'f', 1, 1, 0, 'f', 'menu', NULL, NULL, NULL, NULL, NULL, NULL, '2026-06-17 10:00:31.640482+00', '2026-06-27 13:01:24.318649+00');
-- ----------------------------
-- Primary Key structure for table iam_perm_menu

View File

@@ -1,7 +1,7 @@
package cn.daxpay.open.channel.alipay.client;
import cn.daxpay.open.channel.alipay.dto.AlipayPayReq;
import cn.daxpay.open.channel.alipay.dto.AlipayPayResp;
import cn.daxpay.open.channel.alipay.client.req.AlipayPayReq;
import cn.daxpay.open.channel.alipay.client.resp.AlipayPayResp;
import cn.daxpay.open.payment.common.result.DaxResult;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;

View File

@@ -0,0 +1,33 @@
package cn.daxpay.open.channel.alipay.client.credential;
import lombok.Data;
/// # 支付宝 SDK 凭证
///
/// 与子应用 dax-pay-channel-one 的 `AlipaySdkCredential` 镜像, 跨 HTTP 传输时字段对齐。
/// 主应用从进件实体提取 appId / 私钥 / 证书后组装, 下发给子应用构建 AlipayClient。
@Data
public class AlipaySdkCredential {
/// 支付宝应用ID
private String aliAppId;
/// 应用私钥
private String privateKey;
/// 支付宝公钥(公钥模式使用)
private String alipayPublicKey;
/// 应用公钥证书内容(证书模式使用)
private String appCert;
/// 支付宝公钥证书内容(证书模式使用)
private String alipayCert;
/// 支付宝根证书内容(证书模式使用)
private String alipayRootCert;
/// 网关地址(为空时按沙箱标志自动选择)
private String serverUrl;
/// 签名类型(默认 RSA2)
private String signType;
/// 鉴权方式(publickey 公钥模式 / cert 证书模式)
private String authType;
/// 是否沙箱环境
private Boolean sandbox;
/// 应用授权令牌(服务商代商户调用时使用)
private String appAuthToken;
}

View File

@@ -0,0 +1,15 @@
package cn.daxpay.open.channel.alipay.client.enums;
/// # 支付内容类型
///
/// 与子应用 dax-pay-channel-one 的 `AlipayPayBodyType` 镜像, 跨 HTTP 传输时按枚举名(name)序列化对齐。
public enum AlipayPayBodyType {
/// 跳转链接(wap / pc 场景, 前端可直接 location.href)
LINK,
/// 二维码内容(qr 扫码场景)
QR_CODE,
/// APP 订单串(app 场景)
ORDER_STR,
/// 标识符(jsapi 场景, 支付宝交易号 tradeNo)
IDENTIFIER;
}

View File

@@ -0,0 +1,19 @@
package cn.daxpay.open.channel.alipay.client.enums;
/// # 支付宝支付方式
///
/// 与子应用 dax-pay-channel-one 的 `AlipayPayMethod` 镜像, 跨 HTTP 传输时按枚举名(name)序列化对齐。
public enum AlipayPayMethod {
/// 手机网站支付(QUICK_WAP_WAY)
WAP,
/// APP 支付(QUICK_MSECURITY_PAY)
APP,
/// 电脑网站支付(FAST_INSTANT_TRADE_PAY)
PC,
/// 扫码预下单(precreate)
QR,
/// 付款码支付(当面付 bar_code 场景, 同步扣款)
BARCODE,
/// 小程序/JSAPI 支付(JSAPI_PAY, alipay.trade.create)
JSAPI;
}

View File

@@ -0,0 +1,34 @@
package cn.daxpay.open.channel.alipay.client.req;
import cn.daxpay.open.channel.alipay.client.credential.AlipaySdkCredential;
import cn.daxpay.open.channel.alipay.client.enums.AlipayPayMethod;
import lombok.Data;
import java.time.OffsetDateTime;
/// # 支付宝通道支付请求
///
/// 与子应用 dax-pay-channel-one 的 `AlipayPayReq` 镜像, 经声明式 HTTP 客户端 [cn.daxpay.open.channel.alipay.client.AlipayChannelClient] 序列化传输, 字段对齐。
@Data
public class AlipayPayReq {
/// 商户订单号(主应用支付交易号, 作为支付宝 out_trade_no)
private String outTradeNo;
/// 订单金额(单位: 分)
private Long amount;
/// 订单标题
private String subject;
/// 订单描述(对应支付宝 body)
private String body;
/// 支付方式
private AlipayPayMethod method;
/// 订单过期时间
private OffsetDateTime expireTime;
/// 异步通知地址
private String notifyUrl;
/// 付款码(BARCODE 付款码支付必填)
private String authCode;
/// 买家标识(JSAPI 小程序支付必填; 2088 开头为支付宝用户ID, 否则视为小程序 openid)
private String openId;
/// 通道调用凭证
private AlipaySdkCredential credential;
}

View File

@@ -0,0 +1,29 @@
package cn.daxpay.open.channel.alipay.client.resp;
import cn.daxpay.open.channel.alipay.client.enums.AlipayPayBodyType;
import lombok.Data;
import java.time.OffsetDateTime;
/// # 支付宝通道支付响应
///
/// 与子应用 dax-pay-channel-one 的 `AlipayPayResp` 镜像, 字段对齐。
@Data
public class AlipayPayResp {
/// 商户订单号(透传 Req.outTradeNo)
private String outTradeNo;
/// 支付宝交易号(trade_no)
private String tradeNo;
/// 支付内容
private String payBody;
/// 支付内容类型
private AlipayPayBodyType payBodyType;
/// 是否已终态完成(BARCODE 付款码可能同步成功)
private Boolean complete;
/// 完成时间
private OffsetDateTime finishTime;
/// 实付金额(单位: 分, BARCODE 同步成功时返回)
private Long realAmount;
/// 买家标识(BARCODE 同步成功时返回买家 openid)
private String buyerId;
}

View File

@@ -1,21 +0,0 @@
package cn.daxpay.open.channel.alipay.dto;
import lombok.Data;
import java.util.Map;
/// # 支付宝通道支付请求
///
/// 与子应用 ChannelPayReq 字段一致, 通过 Jackson 序列化传输
@Data
public class AlipayPayReq {
private String channel;
private String bizOrderNo;
private Long amount;
private String subject;
private String description;
private String method;
private String expireTime;
private String otherMethod;
private Map<String, Object> config;
}

View File

@@ -1,17 +0,0 @@
package cn.daxpay.open.channel.alipay.dto;
import lombok.Data;
/// # 支付宝通道支付响应
///
/// 与子应用 ChannelPayResp 字段一致
@Data
public class AlipayPayResp {
private String bizOrderNo;
private String outOrderNo;
private String transOrderNo;
private String payBody;
private String payBodyType;
private Boolean complete;
private String finishTime;
}

View File

@@ -1,25 +1,27 @@
package cn.daxpay.open.channel.alipay.service.direct;
import cn.daxpay.open.channel.alipay.dao.direct.AlipayDirectAppManager;
import cn.daxpay.open.channel.alipay.client.credential.AlipaySdkCredential;
import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectApp;
import cn.daxpay.open.channel.alipay.entity.direct.AlipayDirectAppKeyConfig;
import cn.daxpay.open.payment.masterdata.constants.product.dao.PayProductConfigManager;
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
import cn.daxpay.open.platform.core.enums.pay.config.PayEnvEnum;
import cn.daxpay.open.platform.core.exception.DataNotExistException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/// # 支付宝直连通道配置组装器
/// # 支付宝直连通道凭证组装器
///
/// 从进件商户对象([AlipayDirectApp] + [AlipayDirectAppKeyConfig])读取密钥/证书,
/// 并补充主应用回调地址(notifyUrl)与沙箱标志(sandbox), 组装为下发给子应用的 config Map
/// 组装为下发给子应用的通道调用凭证 [AlipaySdkCredential]
///
/// 应用解析优先级:能力关联(显式配置 > appType自动推导) > 通道商户首个应用 > 商户号首个应用(兜底)。
///
/// 供支付策略([cn.daxpay.open.channel.alipay.strategy.direct.AlipayDirectPayStrategy])组装通道调用配置
/// 供支付策略([cn.daxpay.open.channel.alipay.strategy.direct.AlipayDirectPayStrategy])组装通道调用凭证
@Slf4j
@Service
@RequiredArgsConstructor
@@ -28,27 +30,33 @@ public class AlipayDirectConfigAssembler {
private final AlipayDirectAppManager alipayDirectAppManager;
private final AlipayDirectAppKeyConfigService alipayDirectAppKeyConfigService;
private final AlipayDirectAppCapabilityService alipayDirectAppCapabilityService;
private final PayProductConfigManager payProductConfigManager;
/// 组装直连商户的通道调用配置(下发给子应用)
/// 组装直连商户的通道调用凭证(下发给子应用)
///
/// @param mchNo 商户号(最终兜底定位应用)
/// @param channelMchNo 通道商户号(路由回填)
/// @param capability 支付能力编码(路由回填,用于选择匹配的应用)
/// @return 通道配置 Map, 字段对齐子应用 `AlipayConfigDto`
public Map<String, Object> buildConfig(String mchNo, String channelMchNo, String capability) {
/// @return 支付宝 SDK 凭证, 字段对齐子应用 AlipaySdkCredential
public AlipaySdkCredential buildConfig(String mchNo, String channelMchNo, String capability) {
AlipayDirectApp app = resolveApp(mchNo, channelMchNo, capability);
AlipayDirectAppKeyConfig keyConfig = alipayDirectAppKeyConfigService.findByAlipayDirectAppId(app.getId());
Map<String, Object> config = new HashMap<>();
config.put("aliAppId", app.getAliAppId());
config.put("privateKey", keyConfig.getPrivateKey());
config.put("alipayPublicKey", keyConfig.getAlipayPublicKey());
config.put("authType", keyConfig.getAuthType());
config.put("appCert", keyConfig.getAppCert());
config.put("alipayCert", keyConfig.getAlipayCert());
config.put("alipayRootCert", keyConfig.getAlipayRootCert());
// TODO notifyUrl/sandbox 后续按业务要求手动组装(来源已迁移至进件配置, 待确认组装方式)
return config;
AlipaySdkCredential credential = new AlipaySdkCredential();
credential.setAliAppId(app.getAliAppId());
credential.setPrivateKey(keyConfig.getPrivateKey());
credential.setAlipayPublicKey(keyConfig.getAlipayPublicKey());
credential.setAuthType(keyConfig.getAuthType());
credential.setAppCert(keyConfig.getAppCert());
credential.setAlipayCert(keyConfig.getAlipayCert());
credential.setAlipayRootCert(keyConfig.getAlipayRootCert());
// 读取支付产品当前生效环境, 判断是否沙箱
boolean sandbox = payProductConfigManager.findByProduct(ProductEnum.ALIPAY.getCode())
.map(c -> PayEnvEnum.SANDBOX.getCode().equals(c.getActiveEnv()))
.orElse(false);
credential.setSandbox(sandbox);
// TODO notifyUrl 后续按业务要求手动组装(来源已迁移至进件配置, 待确认组装方式)
return credential;
}
/// 解析支付使用的应用,优先级:能力关联 > 通道商户首个 > 商户号首个兜底

View File

@@ -1,22 +1,22 @@
package cn.daxpay.open.channel.alipay.service.pay;
import cn.daxpay.open.channel.alipay.client.AlipayChannelClient;
import cn.daxpay.open.channel.alipay.dto.AlipayPayReq;
import cn.daxpay.open.channel.alipay.dto.AlipayPayResp;
import cn.daxpay.open.channel.alipay.client.credential.AlipaySdkCredential;
import cn.daxpay.open.channel.alipay.client.enums.AlipayPayBodyType;
import cn.daxpay.open.channel.alipay.client.enums.AlipayPayMethod;
import cn.daxpay.open.channel.alipay.client.req.AlipayPayReq;
import cn.daxpay.open.channel.alipay.client.resp.AlipayPayResp;
import cn.daxpay.open.payment.common.result.DaxResult;
import cn.daxpay.open.payment.pay.bo.PayTradeResultBo;
import cn.daxpay.open.payment.pay.order.entity.PayTrade;
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayParam;
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
import cn.daxpay.open.platform.core.enums.unipay.PayBodyTypeEnum;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
/// # 支付宝支付执行业务服务
///
/// 通过 [AlipayChannelClient] 调用子应用 dax-pay-channel-one 完成支付宝支付下单。
@@ -30,22 +30,24 @@ public class AlipayPayService {
/// 执行支付宝支付
///
/// @param order 支付订单
/// @param payParam 支付参数
/// @param config 通道调用配置(密钥/证书/回调地址等)
/// @param order 支付订单
/// @param payParam 支付参数
/// @param credential 通道调用凭证(密钥/证书)
/// @return 支付结果
public PayTradeResultBo pay(PayTrade order, NormalPayParam payParam, Map<String, Object> config) {
public PayTradeResultBo pay(PayTrade order, NormalPayParam payParam, AlipaySdkCredential credential) {
// 构建请求
AlipayPayReq req = new AlipayPayReq();
req.setChannel("alipay");
// 使用支付交易号作为商户订单号透传给支付宝, 回调时凭此反查 PayTrade
req.setBizOrderNo(order.getTradeNo());
req.setOutTradeNo(order.getTradeNo());
req.setAmount(payParam.getAmount());
req.setSubject(payParam.getTitle());
req.setDescription(payParam.getDescription());
// 将平台支付方式(PayMethodEnum code)映射为支付宝通道识别码
req.setBody(payParam.getDescription());
// 将平台支付方式(PayMethodEnum code)映射为支付宝通道支付方式
req.setMethod(mapMethod(payParam.getMethod()));
req.setConfig(config);
// 付款码(BARCODE) / 买家标识(JSAPI) 通道专属参数透传
req.setAuthCode(payParam.getAuthCode());
req.setOpenId(payParam.getOpenId());
req.setCredential(credential);
// 调用子应用
DaxResult<AlipayPayResp> result = alipayChannelClient.pay(req);
@@ -56,14 +58,16 @@ public class AlipayPayService {
return toPayResult(result.getData());
}
/// 平台支付方式([PayMethodEnum] code) -> 支付宝通道识别码
private static String mapMethod(String methodCode) {
/// 平台支付方式([PayMethodEnum] code) -> 支付宝通道支付方式
private static AlipayPayMethod mapMethod(String methodCode) {
PayMethodEnum m = PayMethodEnum.findByCode(methodCode);
return switch (m) {
case ALIPAY_PC -> "alipay_page";
case ALIPAY_H5 -> "alipay_wap";
case ALIPAY_APP -> "alipay_app";
case ALIPAY_QR, ALIPAY_ORDER_QR -> "alipay_qr";
case ALIPAY_PC -> AlipayPayMethod.PC;
case ALIPAY_H5 -> AlipayPayMethod.WAP;
case ALIPAY_APP -> AlipayPayMethod.APP;
case ALIPAY_QR, ALIPAY_ORDER_QR -> AlipayPayMethod.QR;
case ALIPAY_BARCODE -> AlipayPayMethod.BARCODE;
case ALIPAY_JSAPI, ALIPAY_MINI -> AlipayPayMethod.JSAPI;
default -> throw new UnsupportedOperationException(
"暂不支持的支付宝支付方式: " + methodCode);
};
@@ -72,26 +76,31 @@ public class AlipayPayService {
/// 解析子应用响应为支付结果 BO
private PayTradeResultBo toPayResult(AlipayPayResp resp) {
PayTradeResultBo bo = new PayTradeResultBo()
.setOutOrderNo(resp.getOutOrderNo())
.setOutOrderNo(resp.getTradeNo())
.setComplete(Boolean.TRUE.equals(resp.getComplete()))
.setPayBody(resp.getPayBody())
.setTransOrderNo(resp.getTransOrderNo());
.setPayBody(resp.getPayBody());
// 支付参数体类型
String payBodyType = resp.getPayBodyType();
if (payBodyType != null) {
for (PayBodyTypeEnum type : PayBodyTypeEnum.values()) {
if (type.getCode().equals(payBodyType)) {
bo.setPayBodyType(type);
break;
}
// 支付内容类型映射(子应用 AlipayPayBodyType -> 平台 PayBodyTypeEnum)
AlipayPayBodyType bodyType = resp.getPayBodyType();
if (bodyType != null) {
switch (bodyType) {
case LINK -> bo.setPayBodyType(PayBodyTypeEnum.LINK);
case QR_CODE -> bo.setPayBodyType(PayBodyTypeEnum.QR_CODE);
case ORDER_STR, IDENTIFIER -> bo.setPayBodyType(PayBodyTypeEnum.IDENTIFIER);
}
}
// 完成时间
String finishTime = resp.getFinishTime();
if (finishTime != null && !finishTime.isBlank()) {
bo.setFinishTime(OffsetDateTime.parse(finishTime, DateTimeFormatter.ISO_DATE_TIME));
if (resp.getFinishTime() != null) {
bo.setFinishTime(resp.getFinishTime());
}
// 实付金额(BARCODE 付款码同步成功时返回)
if (resp.getRealAmount() != null) {
bo.setRealAmount(resp.getRealAmount());
}
// 买家标识(BARCODE 付款码同步成功时返回)
if (StrUtil.isNotBlank(resp.getBuyerId())) {
bo.setBuyerId(resp.getBuyerId());
}
return bo;

View File

@@ -11,15 +11,11 @@ import lombok.experimental.Accessors;
@Schema(title = "支付调试结果")
public class DevelopPayResult {
/// 发送的请求体 JSON
@Schema(description = "请求体JSON")
private String requestBody;
/// 签名信息(传入私钥时返回)
@Schema(description = "签名信息")
private DevelopSignResult signInfo;
/// 支付结果
@Schema(description = "支付结果")
private NormalPayResult payResult;
/// 响应签名(平台私钥签名, 可用于验证响应完整性)
@Schema(description = "响应签名")
private String sign;
}

View File

@@ -3,6 +3,7 @@ package cn.daxpay.open.payment.admin.service.develop;
import cn.daxpay.open.payment.admin.param.develop.DevelopParam;
import cn.daxpay.open.payment.admin.result.develop.DevelopPayResult;
import cn.daxpay.open.payment.admin.result.develop.DevelopSignResult;
import cn.daxpay.open.payment.common.context.PaymentAssistService;
import cn.daxpay.open.payment.common.context.PaymentContextManager;
import cn.daxpay.open.payment.common.util.ObjectSignStrUtil;
import cn.daxpay.open.payment.common.util.PaySignUtil;
@@ -12,7 +13,9 @@ import cn.daxpay.open.payment.merchant.service.route.support.PayRouteStrategyCap
import cn.daxpay.open.payment.pay.service.NormalPayService;
import cn.daxpay.open.payment.unipay.param.trade.pay.NormalPayParam;
import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayResult;
import cn.daxpay.open.platform.common.json.util.JsonUtil;
import cn.daxpay.open.platform.common.config.properties.PlatformConfigProperties;
import cn.daxpay.open.platform.core.code.CommonErrorCode;
import cn.daxpay.open.platform.core.exception.BizInfoException;
import cn.daxpay.open.platform.core.rest.dto.LabelValue;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
@@ -32,6 +35,8 @@ public class DevelopTradeService {
private final NormalPayService normalPayService;
private final PaymentContextManager paymentContextManager;
private final PaymentAssistService paymentAssistService;
private final PlatformConfigProperties platformConfigProperties;
private final PayProviderMethodService payProviderMethodService;
private final PayRouteStrategyCapabilitySupport payRouteStrategyCapabilitySupport;
@@ -45,24 +50,35 @@ public class DevelopTradeService {
}
/// 支付调试(真实发起)
///
/// 安全流程与正式支付一致:
/// 1. 使用传入的商户私钥对参数签名, 再用系统配置的商户公钥验签, 校验私钥是否正确
/// 2. 发起真实支付
/// 3. 使用平台私钥对支付结果签名, 便于客户端验证响应完整性
public DevelopPayResult pay(DevelopParam<NormalPayParam> param) {
NormalPayParam payParam = param.getParam();
// 记录发送的请求体
String requestBody = JsonUtil.toJsonStr(payParam);
// 签名信息(传入私钥时生成, 便于核对)
DevelopSignResult signInfo = null;
if (StrUtil.isNotBlank(param.getPrivateKey())) {
signInfo = this.sign(param);
// 私钥必填
if (StrUtil.isBlank(param.getPrivateKey())) {
throw new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR, "pay.error.assist.privateKeyEmpty");
}
// 在支付作用域内执行, 初始化商户上下文, 使 mchNo/appId 等字段自动填充
NormalPayResult payResult = paymentContextManager.executeWithScope(
return paymentContextManager.executeWithScope(
payParam.getMchNo(), payParam.getAppId(),
() -> normalPayService.pay(payParam)
() -> {
// 私钥验证: 用传入私钥签名, 再用系统配置的商户公钥验签
String sign = PaySignUtil.sign(payParam, param.getPrivateKey());
payParam.setSign(sign);
paymentAssistService.signVerify(payParam);
// 发起真实支付
NormalPayResult payResult = normalPayService.pay(payParam);
// 使用平台私钥对支付结果签名
String platformPrivateKey = platformConfigProperties.getKeyConfig().getPrivateKey();
String resultSign = PaySignUtil.sign(payResult, platformPrivateKey);
return new DevelopPayResult()
.setPayResult(payResult)
.setSign(resultSign);
}
);
return new DevelopPayResult()
.setRequestBody(requestBody)
.setSignInfo(signInfo)
.setPayResult(payResult);
}
/// 已启用渠道支付方式目录(供调试页支付方式下拉)

View File

@@ -3,5 +3,6 @@
"jsapi": "JSAPI Object",
"from": "Form Data",
"identifier": "Identifier",
"qr_code": "QR Code",
"json": "JSON Object"
}

View File

@@ -69,6 +69,7 @@
},
"assist": {
"mchPublicKeyEmpty": "Merchant public key is empty",
"privateKeyEmpty": "Merchant private key is empty",
"signEmpty": "Signature is empty",
"mchNoAppNoMatch": "Merchant number and application number do not match",
"mchNotOwnApp": "Merchant does not own this application",

View File

@@ -3,5 +3,6 @@
"jsapi": "JSAPI对象",
"from": "表单数据",
"identifier": "标识码",
"qr_code": "二维码",
"json": "JSON对象"
}

View File

@@ -68,6 +68,7 @@
},
"assist": {
"mchPublicKeyEmpty": "商户公钥为空",
"privateKeyEmpty": "商户私钥为空",
"signEmpty": "签名为空",
"mchNoAppNoMatch": "商户号和应用号不匹配",
"mchNotOwnApp": "该商户不拥有该应用",

View File

@@ -18,6 +18,8 @@ public enum PayBodyTypeEnum implements I18nSupport {
FROM("from"),
/// 标识码
IDENTIFIER("identifier"),
/// 二维码内容(前端渲染成二维码图片)
QR_CODE("qr_code"),
/// JSON对象
JSON("json");

View File

@@ -23,7 +23,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/// 公告管理(管理端)
@PermCode(menuCode = "system:notify")
@PermCode(menuCode = "system:notify:notice")
@Validated
@Tag(name = "公告管理")
@RestController