✨ Introducing new features. #2351 【支付管理】支持YunGouOS 小微商户支付模式

This commit is contained in:
lbw committed 2021-02-03 13:18:29 +08:00
1 parent 821580737c
commit eb8bd5b2d1
15 files changed
+245 -277

No files matched your search

@@ -1,27 +0,0 @@
package com.pig4cloud.pigx.pay.config;
import lombok.Data;
/**
* @author lengleng
* @date 2019-06-19
*/
@Data
public class AliPayConfig {
/**
* 订单过期时间
*/
private String expireTime;
/**
* 前端回调地址
*/
private String returnUrl;
/**
* 服务端回调地址
*/
private String notifyUrl;
}
@@ -1,128 +0,0 @@
package com.pig4cloud.pigx.pay.config;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.pig4cloud.pigx.admin.api.feign.RemoteTenantService;
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.data.tenant.TenantBroker;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.service.PayChannelService;
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.ChannelTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.scheduling.annotation.Async;
/**
* @author lengleng
* @date 2019-05-31
* <p>
* 支付参数初始化
*/
@Slf4j
@Configuration
@AllArgsConstructor
public class PayConfigParmaInitRunner {
public static Map<String, WxMpService> mpServiceMap = new HashMap<>();
private final PayChannelService channelService;
private final RemoteTenantService tenantService;
@Async
@Order
@EventListener({ WebServerInitializedEvent.class })
public void initPayConfig() {
List<PayChannel> channelList = new ArrayList<>();
tenantService.list(SecurityConstants.FROM_IN).getData()
.forEach(tenant -> TenantBroker.runAs(tenant.getId(), (id) -> {
List<PayChannel> payChannelList = channelService.list(
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getState, CommonConstants.STATUS_NORMAL));
channelList.addAll(payChannelList);
}));
channelList.forEach(channel -> {
JSONObject params = JSONUtil.parseObj(channel.getParam());
// 支付宝支付
if (PayChannelNameEnum.ALIPAY_WAP.getName().equals(channel.getChannelId())) {
AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder().setAppId(channel.getAppId())
.setPrivateKey(params.getStr("privateKey")).setCharset(CharsetUtil.UTF_8)
.setAliPayPublicKey(params.getStr("publicKey")).setServiceUrl(params.getStr("serviceUrl"))
.setSignType("RSA2").build();
AliPayApiConfigKit.putApiConfig(aliPayApiConfig);
log.info("新增支付宝支付参数 {}", aliPayApiConfig);
}
// 微信支付
if (PayChannelNameEnum.WEIXIN_MP.getName().equals(channel.getChannelId())) {
WxPayApiConfig wx = WxPayApiConfig.builder().appId(channel.getAppId()).mchId(channel.getChannelMchId())
.partnerKey(params.getStr("paternerKey")).build();
String subMchId = params.getStr("subMchId");
if (StrUtil.isNotBlank(subMchId)) {
wx.setSlAppId(channel.getAppId());
wx.setSlMchId(subMchId);
}
WxPayApiConfigKit.putApiConfig(wx);
WxMpService wxMpService = new WxMpServiceImpl();
WxMpDefaultConfigImpl storage = new WxMpDefaultConfigImpl();
storage.setAppId(channel.getAppId());
storage.setSecret(params.getStr("secret"));
storage.setToken(params.getStr("token"));
wxMpService.setWxMpConfigStorage(storage);
mpServiceMap.put(channel.getAppId(), wxMpService);
log.info("新增微信支付参数 {} {}", wx, wxMpService);
}
});
}
/**
* redis 监听配置,监听 pay_redis_route_reload_topic,重新加载配置
* @param redisConnectionFactory redis 配置
* @return
*/
@Bean
public RedisMessageListenerContainer redisContainer(RedisConnectionFactory redisConnectionFactory) {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener((message, bytes) -> {
log.warn("接收到Redis 事件 重新加载支付参数事件");
initPayConfig();
}, new ChannelTopic(CacheConstants.PAY_REDIS_RELOAD_TOPIC));
return container;
}
}
@@ -1,22 +0,0 @@
package com.pig4cloud.pigx.pay.config;
import lombok.Data;
/**
* @author lengleng
* @date 2019-06-19
*/
@Data
public class WxPayConfig {
/**
* 服务端回调地址
*/
private String notifyUrl;
/**
* 订单过期时间
*/
private String expireTime;
}
@@ -19,16 +19,21 @@ package com.pig4cloud.pigx.pay.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.service.PayChannelService;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 渠道
@@ -44,8 +49,6 @@ public class PayChannelController {
private final PayChannelService payChannelService;
private final RedisTemplate redisTemplate;
/**
* 分页查询
* @param page 分页对象
@@ -77,7 +80,6 @@ public class PayChannelController {
@PreAuthorize("@pms.hasPermission('pay_paychannel_add')")
public R save(@RequestBody PayChannel payChannel) {
payChannelService.saveChannel(payChannel);
redisTemplate.convertAndSend(CacheConstants.PAY_REDIS_RELOAD_TOPIC, "重新加载支付参数");
return R.ok();
}
@@ -91,7 +93,6 @@ public class PayChannelController {
@PreAuthorize("@pms.hasPermission('pay_paychannel_edit')")
public R updateById(@RequestBody PayChannel payChannel) {
payChannelService.updateById(payChannel);
redisTemplate.convertAndSend(CacheConstants.PAY_REDIS_RELOAD_TOPIC, "重新加载支付参数");
return R.ok();
}
@@ -105,7 +106,6 @@ public class PayChannelController {
@PreAuthorize("@pms.hasPermission('pay_paychannel_del')")
public R removeById(@PathVariable Integer id) {
payChannelService.removeById(id);
redisTemplate.convertAndSend(CacheConstants.PAY_REDIS_RELOAD_TOPIC, "重新加载支付参数");
return R.ok();
}
@@ -17,24 +17,37 @@
package com.pig4cloud.pigx.pay.controller;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.util.URLUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.pay.config.PayConfigParmaInitRunner;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.service.PayChannelService;
import com.pig4cloud.pigx.pay.service.PayGoodsOrderService;
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
import com.pig4cloud.pigx.pay.utils.PayConstants;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
@@ -51,6 +64,7 @@ import java.util.Map;
* @author lengleng
* @date 2019-05-28 23:58:27
*/
@Slf4j
@Controller
@AllArgsConstructor
@RequestMapping("/goods")
@@ -59,37 +73,44 @@ public class PayGoodsOrderController {
private final PayGoodsOrderService payGoodsOrderService;
private final PayChannelService channelService;
private final ObjectMapper objectMapper;
/**
* 商品订单
*
* @param goods 商品
* @param goods 商品
* @param response
*
* AliPayApiConfigKit.setAppId WxPayApiConfigKit.setAppId shezhi
*
*/
@SneakyThrows
@Inner(false)
@GetMapping(value = {"/buy", "/merge/buy"})
@GetMapping("/buy")
@SysLog("购买商品")
public void buy(PayGoodsOrder goods, HttpServletRequest request, HttpServletResponse response) {
String ua = request.getHeader(HttpHeaders.USER_AGENT);
//服务商 模式
if ("/goods/merge/buy".equals(request.getRequestURI())) {
Map<String, Object> result = payGoodsOrderService.buy(goods, true);
response.setContentType(ContentType.JSON.getValue());
response.getWriter().print(objectMapper.writeValueAsString(result));
return;
}
log.info("当前扫码方式 UA:{}", ua);
if (ua.contains(PayConstants.MICRO_MESSENGER)) {
String appId = WxPayApiConfigKit.getWxPayApiConfig().getAppId();
String wxUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s"
+ "&redirect_uri=http%3a%2f%2fadmin.pig4cloud.com%2fpay%2fgoods%2fwx%3famount%3d"
+ "%s&response_type=code&scope=snsapi_base&state=";
PayChannel channel = channelService.getOne(
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.WEIXIN_MP),
false);
response.sendRedirect(String.format(wxUrl, appId, goods.getAmount(), appId));
if (channel == null) {
throw new IllegalArgumentException("公众号支付配置不存在");
}
String wxUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s"
+ "&redirect_uri=%s&response_type=code&scope=snsapi_base&state=%s";
String redirectUri = String.format("%s/pay/goods/wx?amount=%s&TENANT-ID=%s", channel.getNotifyUrl(),
goods.getAmount(), TenantContextHolder.getTenantId());
response.sendRedirect(
String.format(wxUrl, channel.getAppId(), URLUtil.encode(redirectUri), channel.getAppId()));
}
if (ua.contains(PayConstants.ALIPAY)) {
@@ -98,12 +119,20 @@ public class PayGoodsOrderController {
}
@SneakyThrows
@Inner(false)
@GetMapping("/merge/buy")
@SysLog("聚合支付购买商品")
public void mergeBuy(PayGoodsOrder goods, HttpServletResponse response) {
Map<String, Object> result = payGoodsOrderService.buy(goods, true);
response.setContentType(ContentType.JSON.getValue());
response.getWriter().print(objectMapper.writeValueAsString(result));
}
/**
* oauth
*
* @param goods 商品信息
* @param state appid
* @param code 回调code
* @param goods 商品信息
* @param code 回调code
* @param modelAndView
* @return
* @throws WxErrorException
@@ -111,10 +140,23 @@ public class PayGoodsOrderController {
@Inner(false)
@SneakyThrows
@GetMapping("/wx")
public ModelAndView wx(PayGoodsOrder goods, String state, String code, ModelAndView modelAndView) {
WxMpService wxMpService = PayConfigParmaInitRunner.mpServiceMap.get(state);
WxMpOAuth2AccessToken wxMpOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
goods.setUserId(wxMpOAuth2AccessToken.getOpenId());
public ModelAndView wx(PayGoodsOrder goods, String code, ModelAndView modelAndView) {
PayChannel channel = channelService.getOne(
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.WEIXIN_MP), false);
if (channel == null) {
throw new IllegalArgumentException("公众号支付配置不存在");
}
JSONObject params = JSONUtil.parseObj(channel.getParam());
WxMpService wxMpService = new WxMpServiceImpl();
WxMpDefaultConfigImpl storage = new WxMpDefaultConfigImpl();
storage.setAppId(channel.getAppId());
storage.setSecret(params.getStr("secret"));
wxMpService.setWxMpConfigStorage(storage);
WxMpOAuth2AccessToken mpOAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
goods.setUserId(mpOAuth2AccessToken.getOpenId());
goods.setAmount(goods.getAmount());
modelAndView.setViewName("pay");
modelAndView.addAllObjects(payGoodsOrderService.buy(goods, false));
@@ -17,6 +17,8 @@
package com.pig4cloud.pigx.pay.entity;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
@@ -25,8 +27,6 @@ import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 渠道
*
@@ -67,6 +67,16 @@ public class PayChannel extends Model<PayChannel> {
*/
private String channelMchId;
/**
* 前端回调地址
*/
private String returnUrl;
/**
* 后端回调地址
*/
private String notifyUrl;
/**
* 渠道状态
*/
@@ -1,5 +1,6 @@
package com.pig4cloud.pigx.pay.handler;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
@@ -11,6 +12,13 @@ import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
*/
public interface PayOrderHandler {
/**
* 准备支付参数
*/
default PayChannel preparePayParams() {
return null;
}
/**
* 创建商品订单
* @param goodsOrder 金额
@@ -18,10 +18,12 @@
package com.pig4cloud.pigx.pay.handler.impl;
import com.pig4cloud.pigx.common.sequence.sequence.Sequence;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
import com.pig4cloud.pigx.pay.handler.PayOrderHandler;
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
import org.springframework.beans.factory.annotation.Autowired;
@@ -55,10 +57,15 @@ public abstract class AbstractPayOrderHandler implements PayOrderHandler {
*/
@Override
public Object handle(PayGoodsOrder payGoodsOrder) {
PayChannel payChannel = preparePayParams();
ChannelPayApiConfigKit.put(payChannel);
createGoodsOrder(payGoodsOrder);
PayTradeOrder tradeOrder = createTradeOrder(payGoodsOrder);
Object result = pay(payGoodsOrder, tradeOrder);
updateOrder(payGoodsOrder, tradeOrder);
// 情况ttl
ChannelPayApiConfigKit.remove();
return result;
}
@@ -17,15 +17,12 @@
package com.pig4cloud.pigx.pay.handler.impl;
import java.util.Map;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayNotifyRecord;
@@ -40,8 +37,6 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.Map;
/**
* @author lengleng
* @date 2019-06-27
@@ -100,28 +95,7 @@ public class AlipayPayNotifyCallbackHandler extends AbstractPayNotifyCallbakHand
*/
@Override
public Boolean verifyNotify(Map<String, String> params) {
String callReq = MapUtil.join(params, StrUtil.DASHED, StrUtil.DASHED);
log.info("支付宝发起回调 报文: {}", callReq);
String appId = params.get("app_id");
if (StrUtil.isBlank(appId)) {
log.warn("支付宝回调报文 appid 为空 {}", callReq);
return false;
}
AliPayApiConfig apiConfig = AliPayApiConfigKit.getApiConfig(appId);
if (apiConfig == null) {
log.warn("支付宝回调报文 appid 不合法 {}", callReq);
return false;
}
try {
return AlipaySignature.rsaCheckV1(params, apiConfig.getAliPayPublicKey(), CharsetUtil.UTF_8, "RSA2");
}
catch (AlipayApiException e) {
log.error("支付宝验签失败", e);
return false;
}
return true;
}
/**
@@ -17,28 +17,36 @@
package com.pig4cloud.pigx.pay.handler.impl;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.api.domain.AlipayTradeWapPayModel;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.alipay.AliPayApiConfigKit;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.pay.config.PayCommonProperties;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
import com.pig4cloud.pigx.pay.mapper.PayChannelMapper;
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
import com.pig4cloud.pigx.pay.mapper.PayTradeOrderMapper;
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author lengleng
* @date 2019-05-31
@@ -50,16 +58,37 @@ import java.io.IOException;
@AllArgsConstructor
public class AlipayWapPayOrderHandler extends AbstractPayOrderHandler {
private final PayCommonProperties payCommonProperties;
private final PayTradeOrderMapper tradeOrderMapper;
private final PayGoodsOrderMapper goodsOrderMapper;
private final PayChannelMapper channelMapper;
private final HttpServletRequest request;
private final HttpServletResponse response;
/**
* 准备支付参数
*/
@Override
public PayChannel preparePayParams() {
PayChannel channel = channelMapper.selectOne(
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.ALIPAY_WAP.name()));
if (channel == null) {
throw new IllegalArgumentException("支付宝网页支付渠道配置为空");
}
JSONObject params = JSONUtil.parseObj(channel.getParam());
AliPayApiConfig aliPayApiConfig = AliPayApiConfig.builder().setAppId(channel.getAppId())
.setPrivateKey(params.getStr("privateKey")).setCharset(CharsetUtil.UTF_8)
.setAliPayPublicKey(params.getStr("publicKey")).setServiceUrl(params.getStr("serviceUrl"))
.setSignType("RSA2").build();
AliPayApiConfigKit.putApiConfig(aliPayApiConfig);
return channel;
}
/**
* 创建交易订单
* @param goodsOrder
@@ -74,7 +103,7 @@ public class AlipayWapPayOrderHandler extends AbstractPayOrderHandler {
tradeOrder.setChannelMchId(AliPayApiConfigKit.getAliPayApiConfig().getAppId());
tradeOrder.setClientIp(ServletUtil.getClientIP(request));
tradeOrder.setCurrency("cny");
tradeOrder.setExpireTime(Long.parseLong(payCommonProperties.getAliPayConfig().getExpireTime()));
tradeOrder.setExpireTime(30L);
tradeOrder.setStatus(OrderStatusEnum.INIT.getStatus());
tradeOrder.setBody(goodsOrder.getGoodsName());
tradeOrderMapper.insert(tradeOrder);
@@ -92,15 +121,16 @@ public class AlipayWapPayOrderHandler extends AbstractPayOrderHandler {
model.setBody(tradeOrder.getBody());
model.setSubject(tradeOrder.getBody());
model.setOutTradeNo(tradeOrder.getOrderId());
model.setTimeoutExpress(payCommonProperties.getAliPayConfig().getExpireTime() + "m");
model.setTimeoutExpress("30m");
// 分转成元 并且保留两位
model.setTotalAmount(NumberUtil.div(tradeOrder.getAmount(), "100", 2).toString());
model.setProductCode(goodsOrder.getGoodsId());
model.setPassbackParams(String.valueOf(TenantContextHolder.getTenantId()));
try {
AliPayApi.wapPay(response, model, payCommonProperties.getAliPayConfig().getReturnUrl(),
payCommonProperties.getAliPayConfig().getNotifyUrl());
log.info("拉起支付宝wap 支付参数 {}", model);
AliPayApi.wapPay(response, model, ChannelPayApiConfigKit.get().getReturnUrl(),
ChannelPayApiConfigKit.get().getNotifyUrl() + "/pay/notify/ali/callbak");
}
catch (AlipayApiException e) {
log.error("支付宝手机支付失败", e);
@@ -17,7 +17,14 @@
package com.pig4cloud.pigx.pay.handler.impl;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.enums.TradeType;
import com.ijpay.core.kit.WxPayKit;
@@ -26,11 +33,13 @@ import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.ijpay.wxpay.model.UnifiedOrderModel;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.pay.config.PayCommonProperties;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
import com.pig4cloud.pigx.pay.mapper.PayChannelMapper;
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
import com.pig4cloud.pigx.pay.mapper.PayTradeOrderMapper;
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
import lombok.RequiredArgsConstructor;
@@ -51,14 +60,35 @@ import java.util.Map;
@RequiredArgsConstructor
public class WeChatMpPayOrderHandler extends AbstractPayOrderHandler {
private final PayCommonProperties payCommonProperties;
private final PayTradeOrderMapper tradeOrderMapper;
private final PayGoodsOrderMapper goodsOrderMapper;
private final PayChannelMapper channelMapper;
private final HttpServletRequest request;
/**
* 准备支付参数
* @return PayChannel
*/
@Override
public PayChannel preparePayParams() {
PayChannel channel = channelMapper.selectOne(
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.WEIXIN_MP.name()));
if (channel == null) {
throw new IllegalArgumentException("微信公众号支付渠道配置为空");
}
JSONObject params = JSONUtil.parseObj(channel.getParam());
WxPayApiConfig wx = WxPayApiConfig.builder().appId(channel.getAppId()).mchId(channel.getChannelMchId())
.partnerKey(params.getStr("partnerKey")).build();
WxPayApiConfigKit.putApiConfig(wx);
return channel;
}
/**
* 创建交易订单
* @param goodsOrder
@@ -94,12 +124,12 @@ public class WeChatMpPayOrderHandler extends AbstractPayOrderHandler {
.mch_id(wxPayApiConfig.getMchId()).nonce_str(WxPayKit.generateStr()).body(goodsOrder.getGoodsName())
.attach(TenantContextHolder.getTenantId().toString()).out_trade_no(tradeOrder.getOrderId())
.total_fee(goodsOrder.getAmount()).spbill_create_ip(ip)
.notify_url(payCommonProperties.getWxPayConfig().getNotifyUrl())
.notify_url(ChannelPayApiConfigKit.get().getNotifyUrl() + "/pay/notify/wx/callbak")
.trade_type(TradeType.JSAPI.getTradeType()).openid(goodsOrder.getUserId()).build()
.createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);
String xmlResult = WxPayApi.pushOrder(false, params);
log.info(xmlResult);
log.info("微信统一下单返回 {}", xmlResult);
Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);
String prepayId = resultMap.get("prepay_id");
return WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(), wxPayApiConfig.getPartnerKey(),
@@ -17,11 +17,13 @@
package com.pig4cloud.pigx.pay.handler.impl;
import java.util.HashMap;
import java.util.Map;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayNotifyRecord;
@@ -36,9 +38,6 @@ import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
/**
* @author lengleng
* @date 2019-06-27
@@ -91,11 +90,6 @@ public class WeChatPayNotifyCallbackHandler extends AbstractPayNotifyCallbakHand
*/
@Override
public Boolean verifyNotify(Map<String, String> params) {
if (!WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getApiKey())) {
log.warn("微信支付回调验签失败", params);
return null;
}
return true;
}
@@ -5,6 +5,7 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayNotifyRecord;
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
@@ -46,7 +47,8 @@ public class YungouosMergePayNotifyCallbakHandler extends AbstractPayNotifyCallb
*/
@Override
public void before(Map<String, String> params) {
Integer tenant = MapUtil.getInt(params, "attach");
TenantContextHolder.setTenantId(tenant);
}
/**
@@ -1,13 +1,18 @@
package com.pig4cloud.pigx.pay.handler.impl;
import javax.servlet.http.HttpServletRequest;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.servlet.ServletUtil;
import com.ijpay.wxpay.WxPayApiConfigKit;
import com.pig4cloud.pigx.pay.config.PayCommonProperties;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pig4cloud.pigx.common.data.tenant.TenantContextHolder;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import com.pig4cloud.pigx.pay.entity.PayGoodsOrder;
import com.pig4cloud.pigx.pay.entity.PayTradeOrder;
import com.pig4cloud.pigx.pay.mapper.PayChannelMapper;
import com.pig4cloud.pigx.pay.mapper.PayGoodsOrderMapper;
import com.pig4cloud.pigx.pay.mapper.PayTradeOrderMapper;
import com.pig4cloud.pigx.pay.utils.ChannelPayApiConfigKit;
import com.pig4cloud.pigx.pay.utils.OrderStatusEnum;
import com.pig4cloud.pigx.pay.utils.PayChannelNameEnum;
import com.yungouos.pay.merge.MergePay;
@@ -15,8 +20,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
/**
* @author lengleng
* @date 2021/1/4
@@ -29,17 +32,32 @@ import javax.servlet.http.HttpServletRequest;
@RequiredArgsConstructor
public class YungouosMergePayOrderHandler extends AbstractPayOrderHandler {
private final PayCommonProperties commonProperties;
private final PayTradeOrderMapper tradeOrderMapper;
private final PayGoodsOrderMapper goodsOrderMapper;
private final PayChannelMapper channelMapper;
private final HttpServletRequest request;
/**
* 准备支付参数
* @return
*/
@Override
public PayChannel preparePayParams() {
PayChannel channel = channelMapper.selectOne(
Wrappers.<PayChannel>lambdaQuery().eq(PayChannel::getChannelId, PayChannelNameEnum.MERGE_PAY.name()));
if (channel == null) {
throw new IllegalArgumentException("聚合支付渠道配置为空");
}
return channel;
}
/**
* 创建交易订单
*
* @param goodsOrder 商品订单
* @return
*/
@@ -49,7 +67,7 @@ public class YungouosMergePayOrderHandler extends AbstractPayOrderHandler {
tradeOrder.setOrderId(goodsOrder.getPayOrderId());
tradeOrder.setAmount(goodsOrder.getAmount());
tradeOrder.setChannelId(PayChannelNameEnum.MERGE_PAY.getName());
tradeOrder.setChannelMchId(WxPayApiConfigKit.getWxPayApiConfig().getMchId());
tradeOrder.setChannelMchId(ChannelPayApiConfigKit.get().getChannelMchId());
tradeOrder.setClientIp(ServletUtil.getClientIP(request));
tradeOrder.setCurrency("CNY");
tradeOrder.setStatus(OrderStatusEnum.INIT.getStatus());
@@ -60,13 +78,14 @@ public class YungouosMergePayOrderHandler extends AbstractPayOrderHandler {
/**
* 调起渠道支付
*
* @param goodsOrder 商品订单
* @param tradeOrder 交易订单
* @return obj
*/
@Override
public Object pay(PayGoodsOrder goodsOrder, PayTradeOrder tradeOrder) {
PayChannel channel = ChannelPayApiConfigKit.get();
String money = NumberUtil.div(tradeOrder.getAmount(), "100", 2).toString();
return MergePay.nativePay(tradeOrder.getOrderId(), money, "100106279016"
, tradeOrder.getBody()
@@ -0,0 +1,29 @@
package com.pig4cloud.pigx.pay.utils;
import com.pig4cloud.pigx.pay.entity.PayChannel;
import lombok.experimental.UtilityClass;
/**
* @author lengleng
* @date 2021/2/2
*
* 聚合支付配置管理
*/
@UtilityClass
public class ChannelPayApiConfigKit {
private static final ThreadLocal<PayChannel> TL = new ThreadLocal();
public PayChannel get() {
return TL.get();
}
public void put(PayChannel channel) {
TL.set(channel);
}
public void remove() {
TL.remove();
}
}