微信支付宝退款

This commit is contained in:
wuchunlei
2023-12-19 17:04:05 +08:00
parent 032cfc9266
commit 229ce39c5e
18 changed files with 617 additions and 159 deletions

View File

@@ -53,6 +53,11 @@ public class WechatPayConfig implements Serializable {
*/
@Value("${wxpay.payUrl}")
private String payUrl;
/**
* pay url
*/
@Value("${wxpay.refundUrl}")
private String refundUrl;
/**
* 回调地址
*/

View File

@@ -1,5 +1,6 @@
package com.peanut.modules.pay.weChatPay.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
@@ -10,6 +11,7 @@ import com.peanut.modules.book.entity.*;
import com.peanut.modules.book.service.*;
import com.peanut.modules.pay.weChatPay.config.WechatPayConfig;
import com.peanut.modules.pay.weChatPay.dto.WechatPaymentInfo;
import com.peanut.modules.pay.weChatPay.service.WxpayService;
import com.peanut.modules.pay.weChatPay.util.HttpUtils;
import com.peanut.modules.pay.weChatPay.util.WechatPayValidator;
import com.peanut.modules.pay.weChatPay.util.WxPayUtil;
@@ -31,41 +33,26 @@ import java.util.stream.Collectors;
@CrossOrigin
@RequestMapping("/pay")
@Configuration
@Transactional(rollbackFor = Exception.class)
public class WeChatPayController {
@Autowired
private MyUserService userService;
@Autowired
private BuyOrderService buyOrderService;
@Autowired
private BuyOrderProductDao buyOrderProductDao;
@Autowired
@Lazy
private WechatPayConfig wechatPayConfig;
@Autowired
private BookBuyConfigService bookBuyConfigService;
@Autowired
private PayWechatOrderService payWechatOrderService;
@Autowired
private PayPaymentOrderService payPaymentOrderService;
@Autowired
private TransactionDetailsService transactionDetailsService;
@Autowired
private ShopProductBookService shopProductBookService;
@Autowired
private UserEbookBuyService userEbookBuyService;
@Autowired
private WxPayUtil wxPayUtil;
@Autowired
private WxpayService wxpayService;
/**
* 生成预订单
*
@@ -74,8 +61,7 @@ public class WeChatPayController {
* @throws Exception
*/
@RequestMapping(value = "/placeAnOrder/shoppingPay")
@Transactional(rollbackFor = Exception.class)
public R newShoppingPay(@RequestBody WechatPaymentInfo paymentInfo) {
public R newShoppingPay(@RequestBody WechatPaymentInfo paymentInfo){
QueryWrapper<BuyOrder> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_sn", paymentInfo.getOrderSn());
BuyOrder order = buyOrderService.getOne(queryWrapper);
@@ -114,122 +100,28 @@ public class WeChatPayController {
*/
@PostMapping("/payNotify")
@Transactional
public R payNotify(HttpServletRequest request, HttpServletResponse response) {
log.info("微信支付回调");
// 处理通知参数
Map<String, Object> bodyMap = getNotifyBody(request);
if (bodyMap == null) {
return null;
}
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 1);
String orderNo = resourceMap.get("out_trade_no").toString();
// 根据订单号,做幂等处理,并且在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱
BuyOrder order = this.buyOrderService.getOne(new QueryWrapper<BuyOrder>().eq("order_sn", orderNo));
// 1.根据订单id获取订单信息
if ("order".equals(order.getOrderType())) {
BuyOrder orderEntity = buyOrderService.getBaseMapper().selectOne(new QueryWrapper<BuyOrder>().eq("order_sn", orderNo));
BigDecimal realMoney = orderEntity.getRealMoney();
// 查询订单的所有 book_id
List<Integer> orderBookIdList = shopProductBookService.getOrderBookId(order.getOrderSn());
// 去重
Set<Integer> set = new HashSet<>(orderBookIdList);
orderBookIdList.clear();
orderBookIdList.addAll(set);
// 查询用户的所有 book_id
List<Integer> userBookIdList = userEbookBuyService.getUserBookId(order.getUserId());
// 取差集
orderBookIdList.removeAll(userBookIdList);
// 为用户添加书籍
List<UserEbookBuyEntity> userEbookBuyEntities = new ArrayList<>();
for (Integer bookId : orderBookIdList) {
UserEbookBuyEntity entity = new UserEbookBuyEntity();
entity.setUserId(order.getUserId());
entity.setBookId(bookId);
userEbookBuyEntities.add(entity);
}
userEbookBuyService.saveBatch(userEbookBuyEntities);
//手摸脚模购买后会开启用户的脉穴的功能
List<Integer> collect = buyOrderProductDao.selectList(new LambdaQueryWrapper<BuyOrderProduct>().eq(BuyOrderProduct::getOrderId, order.getOrderId())).stream().map(BuyOrderProduct::getProductId).collect(Collectors.toList());
if(collect.contains(128)||collect.contains(129)||collect.contains(130)||collect.contains(131)||collect.contains(136)){
MyUserEntity userInfo = userService.getById(order.getUserId());
userInfo.setPointPower(1);
userService.updateById(userInfo);
}
if(collect.contains(133)||collect.contains(134)||collect.contains(135)){
MyUserEntity userInfo = userService.getById(order.getUserId());
userInfo.setTgdzPower(1);
userService.updateById(userInfo);
}
if(collect.contains(39)||collect.contains(62)||collect.contains(123)||collect.contains(127)){
MyUserEntity userInfo = userService.getById(order.getUserId());
userInfo.setWylqPower(1);
userService.updateById(userInfo);
}
public void payNotify(HttpServletRequest request, HttpServletResponse response){
wxpayService.payNotify(request);
}
/**
* 微信退款申请
*/
@RequestMapping("/refund" )
public R refund(@RequestBody Map<String,Object> map){
return R.ok(wxpayService.refund(map));
}
buyOrderService.updateOrderStatus(order.getUserId(), order.getOrderSn(), "0");
}
if ("point".equals(order.getOrderType())) {
PayWechatOrderEntity buy_order_id = payWechatOrderService.getBaseMapper().selectOne(new QueryWrapper<PayWechatOrderEntity>().eq("order_sn", order.getOrderSn()));
Integer buyorder = buy_order_id.getBuyOrderId();
BookBuyConfigEntity bookBuyConfigEntity = bookBuyConfigService.getById(buyorder);
String realMoney = bookBuyConfigEntity.getRealMoney();
int money = Integer.parseInt(realMoney);
userService.rechargeHSPoint(order.getUserId(), money);
TransactionDetailsEntity transactionDetailsEntity = new TransactionDetailsEntity();
transactionDetailsEntity.setUserId(order.getUserId());
transactionDetailsEntity.setChangeAmount(new BigDecimal(money));
transactionDetailsEntity.setOrderType("充值");
transactionDetailsEntity.setRelationId(buy_order_id.getId().intValue());
transactionDetailsEntity.setRemark("充值");
MyUserEntity user = userService.getById(order.getUserId());
BigDecimal peanutCoin = user.getPeanutCoin();
transactionDetailsEntity.setUserBalance(peanutCoin);
transactionDetailsEntity.setUserName(user.getNickname());
transactionDetailsEntity.setTel(user.getTel());
transactionDetailsService.save(transactionDetailsEntity);
// 插入 花生币 充值记录
PayPaymentOrderEntity payPaymentOrderEntity = new PayPaymentOrderEntity();
payPaymentOrderEntity.setUserId(order.getUserId());
payPaymentOrderEntity.setOrderId(String.valueOf(buy_order_id.getId()));
payPaymentOrderEntity.setRealAmount(new BigDecimal(bookBuyConfigEntity.getRealMoney()));
payPaymentOrderEntity.setRechargeAmount(new BigDecimal(bookBuyConfigEntity.getMoney()));
payPaymentOrderEntity.setRechargeChannel(bookBuyConfigEntity.getQudao());
payPaymentOrderEntity.setRechargeStatus("success");
payPaymentOrderEntity.setSuccessTime(new Date());
payPaymentOrderEntity.setUserName(user.getNickname());
payPaymentOrderEntity.setTel(user.getTel());
payPaymentOrderService.save(payPaymentOrderEntity);
buyOrderService.updateOrderStatus(order.getUserId(), order.getOrderSn(), "2");
}
// 成功应答
return R.ok();
/**
* 微信退款回调
* @return R
*/
@PostMapping("/refundNotify")
public void refundNotify(HttpServletRequest request){
wxpayService.refundNotify(request);
}
private Map<String, Object> getNotifyBody(HttpServletRequest request) {
// 处理通知参数
String body = HttpUtils.readData(request);
log.info("支付回调参数:{}", body);
// 转换为Map
Map<String, Object> bodyMap = JSONObject.parseObject(body, new TypeReference<Map<String, Object>>() {
});
// 微信的通知ID通知的唯一ID
String notifyId = bodyMap.get("id").toString();
// 验证签名信息
try {
WechatPayValidator wechatPayValidator = new WechatPayValidator(wechatPayConfig.getVerifier(), notifyId, body);
if (!wechatPayValidator.validate(request)) {
log.error("通知验签失败");
return null;
}
log.info("通知验签成功");
} catch (Exception e) {
log.error(e.getMessage());
}
return bodyMap;
}
}

View File

@@ -5,13 +5,19 @@ import com.peanut.modules.book.entity.PayWechatOrderEntity;
import com.peanut.modules.pay.weChatPay.dto.WechatPaymentInfo;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Map;
@Service
public interface WxpayService extends IService<PayWechatOrderEntity> {
void prepay(WechatPaymentInfo wechatDto) throws IOException;
void prepay(WechatPaymentInfo wechatDto);
void payNotify(HttpServletRequest request);
String refund(Map<String,Object> map);
void refundNotify(HttpServletRequest request);
}

View File

@@ -2,22 +2,34 @@ package com.peanut.modules.pay.weChatPay.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.peanut.common.exception.RRException;
import com.peanut.modules.book.dao.BuyOrderProductDao;
import com.peanut.modules.book.dao.PayWechatOrderDao;
import com.peanut.modules.book.entity.PayWechatOrderEntity;
import com.peanut.modules.book.service.PayWechatOrderService;
import com.peanut.modules.book.entity.*;
import com.peanut.modules.book.service.*;
import com.peanut.modules.pay.refund.entity.PayRefundOrder;
import com.peanut.modules.pay.refund.service.PayRefundOrderService;
import com.peanut.modules.pay.weChatPay.config.WechatPayConfig;
import com.peanut.modules.pay.weChatPay.dto.WechatPaymentInfo;
import com.peanut.modules.pay.weChatPay.service.WxpayService;
import com.peanut.modules.pay.weChatPay.util.HttpUtils;
import com.peanut.modules.pay.weChatPay.util.WechatPayValidator;
import com.peanut.modules.pay.weChatPay.util.WxPayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
@@ -32,8 +44,33 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
@Autowired
private PayWechatOrderService payWechatOrderService;
@Autowired
private MyUserService userService;
@Autowired
private BuyOrderProductDao buyOrderProductDao;
@Autowired
private BookBuyConfigService bookBuyConfigService;
@Autowired
private PayPaymentOrderService payPaymentOrderService;
@Autowired
private TransactionDetailsService transactionDetailsService;
@Autowired
private ShopProductBookService shopProductBookService;
@Autowired
private UserEbookBuyService userEbookBuyService;
@Autowired
private BuyOrderService buyOrderService;
@Autowired
private PayRefundOrderService refundOrderService;
@Override
public void prepay(WechatPaymentInfo paymentInfo) throws IOException {
public void prepay(WechatPaymentInfo paymentInfo){
Map<String, Object> paramMap = new HashMap<>();
// app id
paramMap.put("appid", wechatPayConfig.getAppId());
@@ -65,4 +102,191 @@ public class WxpayServiceImpl extends ServiceImpl<PayWechatOrderDao, PayWechatOr
}
}
@Override
public void payNotify(HttpServletRequest request){
log.info("微信支付回调");
// 处理通知参数
Map<String, Object> bodyMap = getNotifyBody(request);
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 1);
String orderNo = resourceMap.get("out_trade_no").toString();
//修改微信订单表
MPJLambdaWrapper<PayWechatOrderEntity> wrapper = new MPJLambdaWrapper();
wrapper.eq(PayWechatOrderEntity::getOrderSn,orderNo);
PayWechatOrderEntity payWechatOrderEntity = payWechatOrderService.getOne(wrapper);
payWechatOrderEntity.setOrderId(resourceMap.get("transaction_id").toString());
payWechatOrderService.updateById(payWechatOrderEntity);
// 根据订单号,做幂等处理,并且在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱
BuyOrder order = this.buyOrderService.getOne(new QueryWrapper<BuyOrder>().eq("order_sn", orderNo));
// 1.根据订单id获取订单信息
if ("order".equals(order.getOrderType())) {
BuyOrder orderEntity = buyOrderService.getBaseMapper().selectOne(new QueryWrapper<BuyOrder>().eq("order_sn", orderNo));
BigDecimal realMoney = orderEntity.getRealMoney();
// 查询订单的所有 book_id
List<Integer> orderBookIdList = shopProductBookService.getOrderBookId(order.getOrderSn());
// 去重
Set<Integer> set = new HashSet<>(orderBookIdList);
orderBookIdList.clear();
orderBookIdList.addAll(set);
// 查询用户的所有 book_id
List<Integer> userBookIdList = userEbookBuyService.getUserBookId(order.getUserId());
// 取差集
orderBookIdList.removeAll(userBookIdList);
// 为用户添加书籍
List<UserEbookBuyEntity> userEbookBuyEntities = new ArrayList<>();
for (Integer bookId : orderBookIdList) {
UserEbookBuyEntity entity = new UserEbookBuyEntity();
entity.setUserId(order.getUserId());
entity.setBookId(bookId);
userEbookBuyEntities.add(entity);
}
userEbookBuyService.saveBatch(userEbookBuyEntities);
//手摸脚模购买后会开启用户的脉穴的功能
List<Integer> collect = buyOrderProductDao.selectList(new LambdaQueryWrapper<BuyOrderProduct>().eq(BuyOrderProduct::getOrderId, order.getOrderId())).stream().map(BuyOrderProduct::getProductId).collect(Collectors.toList());
if(collect.contains(128)||collect.contains(129)||collect.contains(130)||collect.contains(131)||collect.contains(136)){
MyUserEntity userInfo = userService.getById(order.getUserId());
userInfo.setPointPower(1);
userService.updateById(userInfo);
}
if(collect.contains(133)||collect.contains(134)||collect.contains(135)){
MyUserEntity userInfo = userService.getById(order.getUserId());
userInfo.setTgdzPower(1);
userService.updateById(userInfo);
}
if(collect.contains(39)||collect.contains(62)||collect.contains(123)||collect.contains(127)){
MyUserEntity userInfo = userService.getById(order.getUserId());
userInfo.setWylqPower(1);
userService.updateById(userInfo);
}
buyOrderService.updateOrderStatus(order.getUserId(), order.getOrderSn(), "0");
}
if ("point".equals(order.getOrderType())) {
PayWechatOrderEntity buy_order_id = payWechatOrderService.getBaseMapper().selectOne(new QueryWrapper<PayWechatOrderEntity>().eq("order_sn", order.getOrderSn()));
Integer buyorder = buy_order_id.getBuyOrderId();
BookBuyConfigEntity bookBuyConfigEntity = bookBuyConfigService.getById(buyorder);
String realMoney = bookBuyConfigEntity.getRealMoney();
int money = Integer.parseInt(realMoney);
userService.rechargeHSPoint(order.getUserId(), money);
TransactionDetailsEntity transactionDetailsEntity = new TransactionDetailsEntity();
transactionDetailsEntity.setUserId(order.getUserId());
transactionDetailsEntity.setChangeAmount(new BigDecimal(money));
transactionDetailsEntity.setOrderType("充值");
transactionDetailsEntity.setRelationId(buy_order_id.getId().intValue());
transactionDetailsEntity.setRemark("充值");
MyUserEntity user = userService.getById(order.getUserId());
BigDecimal peanutCoin = user.getPeanutCoin();
transactionDetailsEntity.setUserBalance(peanutCoin);
transactionDetailsEntity.setUserName(user.getNickname());
transactionDetailsEntity.setTel(user.getTel());
transactionDetailsService.save(transactionDetailsEntity);
// 插入 花生币 充值记录
PayPaymentOrderEntity payPaymentOrderEntity = new PayPaymentOrderEntity();
payPaymentOrderEntity.setUserId(order.getUserId());
payPaymentOrderEntity.setOrderId(String.valueOf(buy_order_id.getId()));
payPaymentOrderEntity.setRealAmount(new BigDecimal(bookBuyConfigEntity.getRealMoney()));
payPaymentOrderEntity.setRechargeAmount(new BigDecimal(bookBuyConfigEntity.getMoney()));
payPaymentOrderEntity.setRechargeChannel(bookBuyConfigEntity.getQudao());
payPaymentOrderEntity.setRechargeStatus("success");
payPaymentOrderEntity.setSuccessTime(new Date());
payPaymentOrderEntity.setUserName(user.getNickname());
payPaymentOrderEntity.setTel(user.getTel());
payPaymentOrderService.save(payPaymentOrderEntity);
buyOrderService.updateOrderStatus(order.getUserId(), order.getOrderSn(), "2");
}
}
@Override
public String refund(Map<String,Object> map){
LambdaQueryWrapper<PayWechatOrderEntity> wrapper = new LambdaQueryWrapper();
wrapper.eq(PayWechatOrderEntity::getOrderSn,map.get("orderSn").toString());
PayWechatOrderEntity order = payWechatOrderService.getOne(wrapper);
Map<String, Object> paramMap = new HashMap<>();
//构建订单金额信息
//退款金额
BigDecimal refund = new BigDecimal(map.get("refundFee").toString());
//原订单总金额
BigDecimal total = order.getTotalAmount();
// 这里 * 100微信支付单位为 ‘分’
BigDecimal hand = new BigDecimal("100");
Map<String, Object> amountMap = new HashMap<>();
amountMap.put("refund", refund.multiply(hand));
amountMap.put("total", total.multiply(hand).intValue());
amountMap.put("currency", "CNY");
paramMap.put("amount", amountMap);
//商户退款单号 商户系统内 部的退款单号商户系统内部唯一只能是数字、大小写字母_-|*@ ,同一退款单号多次请求只退一笔。
// paramMap.put("out_refund_no", map.get("outRefundNo").toString());
paramMap.put("out_refund_no", UUID.randomUUID().toString());
//微信支付订单号
paramMap.put("transaction_id", order.getOrderId());
//退款原因
paramMap.put("reason", map.get("reason").toString());
// 微信退款回调地址
paramMap.put("notify_url", wechatPayConfig.getRefundNotifyUrl());
JSONObject json = JSONObject.parseObject(JSON.toJSONString(paramMap));
log.info("微信退款申请请求参数:{}", paramMap);
log.info(">>>>>>>>>>App请求微信退款申请接口");
JSONObject responseJson = wxPayUtil.doPostWexinV3(wechatPayConfig.getRefundUrl(), json.toJSONString());
log.info(">>>>>>>>>>>微信退款返回的信息是 resJson = {}", responseJson.toJSONString());
if ("SUCCESS".equals(responseJson.get("status"))){
//退款申请成功,等待到账
}
return responseJson.toJSONString();
}
@Override
@Transactional
public void refundNotify(HttpServletRequest request){
log.info("微信退款回调");
// 处理通知参数
Map<String, Object> bodyMap = getNotifyBody(request);
// 解密resource中的通知数据
String resource = bodyMap.get("resource").toString();
Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 2);
log.info("微信退款回调结果 msg={}",resourceMap);
if ("SUCCESS".equals(resourceMap.get("refund_status").toString())){
log.info(">>>>>>>>>>>微信退款成功!<<<<<<<<<<<<<");
MPJLambdaWrapper<BuyOrder> w = new MPJLambdaWrapper();
w.selectAll(BuyOrder.class);
w.leftJoin(PayWechatOrderEntity.class,PayWechatOrderEntity::getOrderSn, BuyOrder::getOrderSn);
w.eq("t1.order_id",resourceMap.get("transaction_id").toString());
BuyOrder order = buyOrderService.getOne(w);
PayRefundOrder refund = new PayRefundOrder();
refund.setPayType("1");
refund.setOrderId(order.getOrderId());
refund.setTradeNo(resourceMap.get("transaction_id").toString());
refund.setOutTradeNo(resourceMap.get("out_trade_no").toString());
refund.setRefundFee(((Map)resourceMap.get("amount")).get("refund").toString());
refundOrderService.save(refund);
refundOrderService.businessOpt(order);
}
}
private Map<String, Object> getNotifyBody(HttpServletRequest request) {
// 处理通知参数
String body = HttpUtils.readData(request);
log.info("支付回调参数:{}", body);
// 转换为Map
Map<String, Object> bodyMap = JSONObject.parseObject(body, new TypeReference<Map<String, Object>>() {
});
// 微信的通知ID通知的唯一ID
String notifyId = bodyMap.get("id").toString();
// 验证签名信息
try {
WechatPayValidator wechatPayValidator = new WechatPayValidator(wechatPayConfig.getVerifier(), notifyId, body);
if (!wechatPayValidator.validate(request)) {
log.error("通知验签失败");
return null;
}
log.info("通知验签成功");
} catch (Exception e) {
log.error(e.getMessage());
}
return bodyMap;
}
}