https://gitee.com/livemetoo/union-pay
收银页面如下:
微信h5支付主要业务流程:
聚合支付平台微信H5支付模块设计
聚合支付平台微信支付数据库设计说明
商户进件表:保存商户进件信息及二级商户基本信息
CREATE TABLE `sub_merchant_info` ( `id` bigint NOT NULL AUTO_INCREMENT, `platform_mch_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '平台服务商商户号', `sub_mch_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '微信支付二级商户号', `merchant_short_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商户简称', `subject_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '主体类型: SUBJECT_TYPE_ENTERPRISE等', `contact_phone` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '联系手机(AEAD_AES_256_GCM加密)', `settlement_account_info` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '结算账户信息(加密存储)', `applyment_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '微信进件申请单号', `redirect_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '同步回调地址', `status` tinyint NOT NULL DEFAULT '0' COMMENT '状态: 0-审核中, 1-已生效, 2-已驳回, 3-已注销', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uk_sub_mch_id` (`sub_mch_id`) USING BTREE, KEY `idx_applyment_id` (`applyment_id`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='二级商户信息表';分帐商户配置表:目前仅有平台商户
CREATE TABLE `profit_sharing_receiver` ( `id` bigint NOT NULL AUTO_INCREMENT, `platform_mch_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '平台商户号', `receiver_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '接收方类型: MERCHANT_ID(商户), PERSONAL_WECHATID(个人)', `receiver_account` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '接收方账号(商户号或openid)', `receiver_name` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '接收方名称(个人需真实姓名, 建议加密)', `relation_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '与平台关系: PLATFORM, SUPPLIER, DISTRIBUTOR', `status` tinyint NOT NULL DEFAULT '0' COMMENT '状态: 0-待添加, 1-已添加, 2-已解除', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uk_receiver` (`platform_mch_id`,`receiver_type`,`receiver_account`) USING BTREE ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='分账接收方配置表';支付订单主表
CREATE TABLE `unified_payment_order` ( `id` varchar(50) NOT NULL, `order_type` tinyint NOT NULL COMMENT '订单类型: 1-普通支付, 2-合单支付', `app_order_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商户平台订单号', `combine_out_trade_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '平台合单/主订单号(32字符内)', `wechat_combine_order_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '微信合单订单号(transaction_id)', `user_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户id', `user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名称', `total_amount` int NOT NULL COMMENT '订单总金额(单位: 分)', `payer_openid` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '支付者openid', `pay_status` tinyint NOT NULL DEFAULT '0' COMMENT '支付状态: 0-待支付, 1-支付成功, 2-已关闭, 3-已退款', `profit_sharing_status` tinyint NOT NULL DEFAULT '0' COMMENT '分账状态: 0-无需分账, 1-待分账, 2-分账中, 3-分账完成, 4-分账失败', `redirect_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '支付回调同步通知地址', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `pay_time` datetime DEFAULT NULL COMMENT '支付成功时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `diff_status` tinyint DEFAULT '0' COMMENT '对账状态:0:未对账:1:对账成功,2:对账失败', `diff_detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '对账明细', `sharing_date` datetime DEFAULT NULL COMMENT '执行分帐时间', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uk_combine_out_trade_no` (`combine_out_trade_no`) USING BTREE, KEY `idx_wechat_order_id` (`wechat_combine_order_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='统一支付主订单表';支付订单子表
CREATE TABLE `sub_order_detail` ( `id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL, `combine_out_trade_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关联的主订单号', `app_order_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '商户平台订单号', `sub_out_trade_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '平台子订单号(32字符内)', `sub_mch_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '二级商户号', `sub_appid` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '二级商户绑定的AppID(如有)', `user_id` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户id', `user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名称', `goods_detail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '商品Tag', `amount` int NOT NULL COMMENT '子订单金额(单位: 分)', `subsidy_amount` int NOT NULL DEFAULT '0' COMMENT '平台补差金额(单位: 分)', `is_profit_sharing` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否指定分账: 1-是, 0-否', `wechat_sub_order_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '微信返回的子订单号', `profit_sharing_status` tinyint NOT NULL DEFAULT '0' COMMENT '该子订单的分账状态: 0-待分账, 1-已完成', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `logistics_price` decimal(10,2) DEFAULT '0.00' COMMENT '物流费用', `merchant_rate_price` decimal(10,2) DEFAULT '0.00' COMMENT '平台抽成比率', `redirect_url` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '同步回调地址', `sharing_date` datetime DEFAULT NULL COMMENT '执行分帐时间', PRIMARY KEY (`id`) USING BTREE, KEY `idx_combine_order` (`combine_out_trade_no`) USING BTREE, KEY `idx_sub_mch_id` (`sub_mch_id`) USING BTREE, KEY `uk_sub_out_trade_no` (`sub_out_trade_no`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='子订单/分账明细表';分帐订单表
CREATE TABLE `profit_sharing_record` ( `id` bigint NOT NULL AUTO_INCREMENT, `combine_out_trade_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '关联的支付订单号', `out_order_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '平台分账订单号(32字符内, 幂等键)', `wechat_order_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '微信订单号(transaction_id)', `total_sharing_amount` int NOT NULL COMMENT '本次分账总金额(单位: 分)', `sharing_status` tinyint NOT NULL DEFAULT '0' COMMENT '分账状态: 0-处理中, 1-成功, 2-失败', `fail_reason` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '失败原因', `is_unfreeze` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否解冻剩余未分账资金: 1-是, 0-否', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `wx_result` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci COMMENT '微信分帐申请结果', `receivers` text COMMENT '分账接收方信息', `sub_mchid` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '出资商户号', PRIMARY KEY (`id`) USING BTREE, UNIQUE KEY `uk_out_order_no` (`out_order_no`) USING BTREE, KEY `idx_wechat_order_id` (`wechat_order_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='分账执行记录表';退款订单表:分为type 1:分帐退款,2:商户退款
CREATE TABLE `pay_refund_record` ( `id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键ID', `type` int unsigned DEFAULT NULL COMMENT '退款类型 :1-商户退款,2-商户分帐退款', `combine_out_trade_no` varchar(64) NOT NULL DEFAULT '' COMMENT '合单商户订单号(对应请求中的combineOutTradeNo)', `out_trade_no` varchar(64) NOT NULL DEFAULT '' COMMENT '子商户订单号(对应微信返回的out_trade_no)', `order_id` varchar(64) NOT NULL DEFAULT '0' COMMENT '本地主订单ID(冗余,便于JOIN查询)', `sp_mchid` varchar(32) NOT NULL DEFAULT '' COMMENT '服务商户号', `sub_mchid` varchar(32) NOT NULL DEFAULT '' COMMENT '子商户号(合单支付必填)', `transaction_id` varchar(64) NOT NULL DEFAULT '' COMMENT '微信支付订单号', `refund_id` varchar(64) NOT NULL DEFAULT '' COMMENT '微信退款单号(唯一标识一笔退款)', `out_refund_no` varchar(64) NOT NULL DEFAULT '' COMMENT '商户退款单号(业务幂等键)', `refund_status` varchar(16) NOT NULL DEFAULT 'PROCESSING' COMMENT '退款状态: PROCESSING/SUCCESS/CLOSED', `success_time` datetime DEFAULT NULL COMMENT '退款成功时间(微信返回,带时区需转换)', `user_received_account` varchar(128) DEFAULT NULL COMMENT '退款入账账户(如:招商银行信用卡)', `refund_account` varchar(32) DEFAULT NULL COMMENT '退款出资账户: REFUND_SOURCE_SUB_MERCHANT等', `total_amount` int unsigned NOT NULL DEFAULT '0' COMMENT '原订单总金额(分)', `refund_amount` int unsigned NOT NULL DEFAULT '0' COMMENT '本次退款金额(分)', `payer_total` int unsigned NOT NULL DEFAULT '0' COMMENT '用户支付金额(分)', `payer_refund` int unsigned NOT NULL DEFAULT '0' COMMENT '用户退款金额(分)', `currency` varchar(8) NOT NULL DEFAULT 'CNY' COMMENT '货币类型', `fail_reason` varchar(512) DEFAULT NULL COMMENT '退款失败原因(CLOSED状态时记录)', `notify_data` text COMMENT '微信回调原始报文(JSON,用于对账和排查)', `remark` varchar(256) DEFAULT NULL COMMENT '业务备注/退款原因', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', PRIMARY KEY (`id`), UNIQUE KEY `uk_out_refund_no` (`out_refund_no`), UNIQUE KEY `uk_refund_id` (`refund_id`), KEY `idx_combine_out_trade_no` (`combine_out_trade_no`), KEY `idx_order_id` (`order_id`), KEY `idx_refund_status` (`refund_status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='支付退款记录表';回调记录表:作为订单补偿策略依据
CREATE TABLE `wechat_pay_notify_log` ( `id` bigint NOT NULL AUTO_INCREMENT, `notify_type` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '回调类型: COMBINE_TRANSACTION, PROFIT_SHARING, REFUND', `out_trade_no` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '商户订单号', `transaction_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '微信订单号', `raw_payload` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '原始回调报文(JSON)', `process_status` tinyint NOT NULL DEFAULT '0' COMMENT '处理状态: 0-待处理, 1-处理成功, 2-处理失败', `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) USING BTREE, KEY `idx_out_trade_no` (`out_trade_no`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=DYNAMIC COMMENT='微信支付回调日志表';聚合支付平台微信支付接口设计说明
接口名称:发起支付(原商户平台APP后台下单接口已经对接,小程序需要更换原商户平台下单接口)
Url: /wx/unified-payment-order/paymentInfo
请求方式:POST
参数:List<SubOrder> subOrders
@Data public class SubOrder { private String mchid; *// 平台商户号-微信端* * *private String mcnName; *//平台商户名称-微信端* * *private String subMchid; *// 平台子商户号-微信端* * *private String merchantId; *//平台子商户号-平台端* * *private String merchantName; *//平台子商户名称-平台端* * *private String appOrderNo; *//商城,小程序端订单号* * *private String appSubOrderNo; *//商城,小程序端子订单号* * *private String attach; *// 附加数据* * *private String userId; private String userName; private Amount amount; *// 金额信息* * *private String outTradeNo; *// 聚合支付平台订单号* * *private String description; *// 订单描述* * *private List<GoodsDetail> goodsDetails; private SettleInfo settleInfo; *// 分账信息* * *private String redirectUrl; }示例:
[ { "mchid": "MCH001", "appOrderNo":"12341234", "mcnName": "伴利科技商户A", "attach": "附加备注信息", "userId": "U100001", "userName": "张三", "amount": { "totalAmount": 100.00, "currency": "CNY" }, "outTradeNo": "SUB202607210001", "description": "高级会员服务-子单1", "subMchid": "SUB_MCH001", "goodsTag": "会员服务", "goodsId": "GOODS001", "settleInfo": { "profitSharing": **false** } }, { "mchid": "MCH002", "appOrderNo":"12341234", "mcnName": "伴利科技商户B", "attach": "附加备注信息", "userId": "U100001", "userName": "张三", "amount": { "totalAmount": 198.00, "currency": "CNY" }, "outTradeNo": "SUB202607210002", "description": "增值工具包-子单2", "subMchid": "SUB_MCH002", "goodsTag": "工具包", "goodsId": "GOODS002", "settleInfo": { "profitSharing": **true** } } ]返回值:收银台H5页面
接口名称:预支付订单
Url: /wx/unified-payment-order/prePayment
请求方式:POST
参数:List<SubOrder> subOrders
private String mchid; *// 平台商户号-微信端* * *private String mcnName; *//平台商户名称-微信端* * *private String subMchid; *// 平台子商户号-微信端* * *private String merchantId; *//平台子商户号-平台端* * *private String merchantName; *//平台子商户名称-平台端* * *private String appOrderNo; *//商城,小程序端订单号* * *private String appSubOrderNo; *//商城,小程序端子订单号* * *private String attach; *// 附加数据* * *private String userId; private String userName; private Amount amount; *// 金额信息* * *private String outTradeNo; *// 聚合支付平台订单号* * *private String description; *// 订单描述* * *private List<GoodsDetail> goodsDetails; private SettleInfo settleInfo; *// 分账信息* * *private String redirectUrl; }返回参数:
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { return Result.<T>*builder*() .code(200) .message("success") .data(data) .build(); } public static <T> Result<T> success() { return *success*(null); } public static <T> Result<T> error(Integer code, String message) { return Result.<T>*builder*() .code(code) .message(message) .build(); } public static <T> Result<T> error(String message) { return *error*(500, message); } }接口名称:发起退款
Url: /payRefundRecord/returnOrder
请求方式:POST
参数:@RequestParam String combineOutTradeNo
返回参数:
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class Result<T> { private Integer code; private String message; private T data; public static <T> Result<T> success(T data) { return Result.<T>*builder*() .code(200) .message("success") .data(data) .build(); } public static <T> Result<T> success() { return *success*(null); } public static <T> Result<T> error(Integer code, String message) { return Result.<T>*builder*() .code(code) .message(message) .build(); } public static <T> Result<T> error(String message) { return *error*(500, message); } }接口名称:平台回调接口,微信H5页面操作支付成功后,跳转到收银台支付成功页面
Url:/wechat/pay/success/{combineOutTradeNo}
请求方式:GET
参数:@PathVariable String combineOutTradeNo
返回参数:支付成功页面
接口名称:微信支付结果异步通知回调
Url:/wechat/pay/notify
请求方式:POST
参数:
@RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Signature") String signature, @RequestHeader("Wechatpay-Serial") String serial, @RequestBody String body返回参数:微信固定返回
{ "code":"SUCCESS", "message": "成功" } { "code":"FAIL", "message": "失败" }接口名称:微信分账结果通知回调
Url:/wechat/pay/notify/sharing
请求方式:POST
参数:
@RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Signature") String signature, @RequestHeader("Wechatpay-Serial") String serial, @RequestBody String body返回参数:微信固定返回
{ "code":"SUCCESS", "message": "成功" } { "code":"FAIL", "message": "失败" }接口名称:微信退款结果通知回调
Url:/wechat/pay/notify/refund
请求方式:POST
参数:
@RequestHeader("Wechatpay-Timestamp") String timestamp, @RequestHeader("Wechatpay-Nonce") String nonce, @RequestHeader("Wechatpay-Signature") String signature, @RequestHeader("Wechatpay-Serial") String serial, @RequestBody String body返回参数:微信固定返回
{ "code":"SUCCESS", "message": "成功" } { "code":"FAIL", "message": "失败" }批次处理任务设计
系统是xxljob调度springbatch结合IO型线程池批处理任务,满足高性能,高可用数据开发标准
任务名称:支付对账
任务:jobHandlerPaymentOrderProcessJob
执行器:xxl-job-union-pay
xxljob周期:0 0 0,2 * * * (每天2点)
任务名称:分帐
任务:jobHandlerPaymentOrderProfitSharingProcessJob
执行器:xxl-job-union-pay
xxljob周期:0 0 0,3 * * * (每天3点)
任务名称:分帐异步确认
任务:jobHandlerProfitsharingQueryOrderProcessJob
执行器:xxl-job-union-pay
xxljob周期:0 0 30,3 * * * (每天3点半)
任务名称:分账回退异步确认
任务:jobHandlerProcessJobQueryReturnOrder
执行器:xxl-job-union-pay
xxljob周期:0 0 0,4 * * * (每天4点)
任务名称:退款异步确认
任务:jobHandlerProcessJobQueryRefundByOutRefundNo
执行器:xxl-job-union-pay
xxljob周期:0 0 0,5 * * * (每天5点)